1. Project Introduction
(1) Function Introduction:
Main business: provide online lottery function for company activities (such as annual meeting, etc.), meet the management of prizes, lottery personnel, and the needs of lottery activities.
- User registration
- User login and session management
- Lottery setup: prize management, lottery personnel management
- Researchers draw
(2) Development environment and Technology stack:
- windows
- Maven
- Lombok
- Spring, SpringMVC, SpringBoot
- MySQL, Mybatis, Druid
(3) Project Demonstration:
User login:
User registration:
Awards:
Sweepstakes Personnel:
Lottery:
2. Project Preparation:
(1) code framework :(source code)
Full source code Github link:Github.com/JACK-QBS/Pr…
(2) Database design:
Database table diagram:
(One-to-one in business)
Why have a setup table?
- A 1-to-1 table can actually use only one table to hold all the fields; However, in some possible business expansion, convenient system expansion use, so when designing tables, consider 1-to-1 design.
- Expand business, a user comes in to set, when multiple users come in to set (multiple users belong to the same company), if it is only the user table, and can not support the business, the user table associated company, set the table in the associated company
3. Realization of back-end to front-end interface:
To implement functions, you need to define the interfaces agreed on the front and back ends. It should be noted that the definition of the interface is generally agreed at the front and back ends, so it is closely related to the front-end code. What data the front end needs and what data format it needs will also be reflected in the interface.
Interfaces are mainly embodied in:
- Request required information: request method, request path, request data
- The response data
(1) User login, registration and logout
User login:
Front-end request:
POST API /user/login (request path)
Content-Type: application/json {username: “qbs”, password: “123”}
Response:
{” success “: true}
Back-end implementation interface:
User registration:
Front-end request:
POST API /user/register (request path)
Content-Type: multipart/form-data; boundary=—- WebKitFormBoundarypOUwkGIMUyL0aOZT
Username: QBS password: 123 nickname: handsome email: [email protected] age: 18 headFile: (binary)Copy the code
Response:
{" success ": true}Copy the code
Back-end implementation:
User logout:
Front-end request:
POST API /user/login (request path)
Back-end implementation:
(2) Query award Settings and modify the number of lottery winners:
For awards:
Front-end request:
GET API /setting/query (request path)
Back-end implementation:
Modify the number of lucky draw:
Front-end request:
GET api/setting/update? BatchNumber =5 (request path)
(On the page of drawing Settings corresponding to the interface, click the drop-down menu of each drawing number to change)
Back-end implementation:
(3) Add, modify and delete awards:
New awards:
Front-end request:
POST API/Award /add (Request path)
Content-Type: application/json
Name: “Special Prize”, Count: 1, Award: “7-day tour around the world”}
Back-end implementation:
Modified awards:
Front-end request:
POST API/Award/Update (Request path)
Content-Type: application/json
Back-end response:
Delete awards:
Front-end request:
GET API /award/delete/4 (request path)
The final number, 4, corresponds to the id of the prize
Back-end implementation:
(4) Add, modify and delete lottery winners:
New sweepstakes:
Front-end request:
POST API /member/add (request path)
Content-Type: application/json
Back-end implementation:
Modify the sweepstakes
Front-end request:
POST api/member/update
Content-Type: application/json
Back-end implementation:
Delete the sweepstakes
Front-end request:
GET api/member/delete/97
(The last number is the ID of the raffle taker)
Back-end implementation:
(5) Lottery and deletion of winners:
Lottery:
Front-end request:
POST api/record/add/3
Content-Type: application/json
(The last number in the path above represents the prize ID, and the requested data is an array of sweepers’ ids)
Back-end implementation:
The record (personnel ID, award ID) is inserted into the back end of the lottery, and the specific lottery is realized in the front end, and it is also a simple way to achieve, without any algorithm. (Only in the remaining quota of the current prize, the number of people in each drawing, in the list of all the unsuccessful winners, randomly selected)
Delete award winners:
Front-end request:
GET api/record/delete/member? id=22
(Delete corresponding award records according to personnel ID)
GET api/record/delete/award? id=3
(Delete records of all winners according to award ID)
Back-end implementation:
4. Code design:
(1) Design the entity class of the database:
Mybatis generation tool (tool package) : generate mapper, database table entity class (model package), XML file
(2) Design unified response class:
The main purpose is to return a uniform field design for data
/** * public class JSONResponse {private Boolean success; private String code; private String message; private Object data; }Copy the code
/ * * * unified data encapsulation * / public class RequestResponseBodyMethodProcessorWrapper implements HandlerMethodReturnValueHandler { private final HandlerMethodReturnValueHandler delegate; public RequestResponseBodyMethodProcessorWrapper(HandlerMethodReturnValueHandler delegate) { this.delegate = delegate; } @Override public boolean supportsReturnType(MethodParameter returnType) { return delegate.supportsReturnType(returnType); } @Override public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {//returnValue Indicates that the Controller request method is finished. The return value if (! (returnValue instanceof JSONResponse)){// returnValue itself is the required type, no processing JSONResponse json = new JSONResponse(); json.setSuccess(true); json.setData(returnValue); returnValue = json; } delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest); }}Copy the code
(3) Designing custom exceptions:
It can locate the meaning of services in different scenarios when exceptions need to be thrown.
It is mainly divided into:
- 1. Exceptions when the client requests errors: The error code needs to be given to facilitate the front end to prompt the user, such as the user name does not allow registration
- 2. Exceptions when business errors occur: Error codes need to be given for the convenience of the back-end to locate problems. Generally, business errors in the program can be thrown (BUG).
- 3, system error occurs when abnormal: need the given error code, convenient and back-end positioning problem, program error, such as database connection for failure can be thrown (general error is the system, such as network was broken and hung up the database, etc.) custom exception front need to display the error code and error message, the user can according to the prompt information to determine the reason.
- 4, non-custom exception, exception information is generally thrown by the framework or JDK in English, is to describe the error for developers, users cannot be prompted, so the error message is unknown exception.
*/ @getter@setter Public Class AppException extends RuntimeException {private String code; public AppException( String code, String message) { super(message); this.code = code; } public AppException( String code, String message, Throwable cause) { super(message, cause); this.code = code; }}Copy the code
@controllerAdvice @slf4j Public Class ExceptionAdvice {// Customize the error code and error message @ExceptionHandler(AppException.class) @responseBody public Object handle1(AppException e){ JSONResponse json = new JSONResponse(); json.setCode(e.getCode()); json.setMessage(e.getMessage()); Log.debug (" custom exception ", e); return json; } // Non-custom exception (English error message, stack information, cannot be shown to the user) : // Specify an error code, error message (unknown error, Please contact the administrator) @ExceptionHandler(exception.class) @responseBody Public Object Handle2 (Exception e){JSONResponse json = new JSONResponse(); json.setCode("ERR000"); Json.setmessage (" Unknown error, please contact administrator "); Log.error (" unknown error ", e); return json; }}Copy the code
(4) Design an interceptor for unified session management
public class LoginInterceptor implements HandlerInterceptor { private ObjectMapper objectMapper; public LoginInterceptor(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(false); if(session ! User User = (User) session.getAttribute(" User "); if(user ! = null){return true; Json // new ObjectMapper().writeasString (object); // New ObjectMapper().writeasString (object); String servletPath = request.getServletPath(); / / / apiXXX. HTML if (servletPath startsWith ("/API/")) {/ / backend logic: returns a json response. SetCharacterEncoding (" utf-8 "); response.setContentType(MediaType.APPLICATION_JSON_VALUE); JSONResponse json = new JSONResponse(); json.setCode("USR000"); Json.setmessage (" User is not logged in, access is not allowed "); String s = objectMapper.writeValueAsString(json); response.setStatus(HttpStatus.UNAUTHORIZED.value()); PrintWriter pw = response.getWriter(); pw.println(s); pw.flush(); }else{// Logic: String schema = request.getScheme(); String schema = request.getScheme(); //http String host = request.getServerName(); //ip int port = request.getServerPort(); //port String contextPath = request.getContextPath(); // Application Context Path Application Context path String basePath = schema+"://"+host+":"+port+contextPath; Response.sendredirect (basePath+"/index.html"); // Redirect to login page response.sendreDirect (basePath+"/index.html"); } return false; }}Copy the code
(5) Design the base class of Mapper in Mybatis:
Using Mybatis interface methods, all interface methods are similar, but the input parameters and return values are different, we can consider the design of a unified base class, in a generic way to define different parameter types, return types
/** * Public interface BaseMapper<T> {int deleteByPrimaryKey(Integer id); int insert(T record); int insertSelective(T record); T selectByPrimaryKey(Integer id); / / by primary key query int updateByPrimaryKeySelective record (T); Int updateByPrimaryKey(T record); }Copy the code