• Previously: This demo is based on Springboot + Mybatis -plus encryption, encryption is the main, global exception processing, log processing as a secondary, and login password encryption is a must in each project, password can not be stored in plain text data, so there is no security.

Related functions, global exception handling, log processing, Mybatis -plus implementation and database interaction, password encryption,restful style

Tools involved: IDEA, Postman, SQLYog (Navicat)

1. Let’s get straight to the results first. If you’re not satisfied, there’s no need to see them

If that’s what you’re looking for, you can move on

2. First, let’s take a look at the POM.xml file

The following dependencies are the primary dependencies required

<?xml version="1.0" encoding="UTF-8"? >
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.4. RELEASE</version>
        <relativePath/> <! -- lookup parent from repository -->
    </parent>
    <groupId>com.jgsu</groupId>
    <artifactId>springboot_rsa_encryption</artifactId>
    <version>0.0.1 - the SNAPSHOT</version>
    <name>springboot_encryption</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <! -- WEB dependency -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <! -- Hot deployment dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <! Mysql > connect to database
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <! -- Lombok dependencies, simplifying set/get methods -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>

        <! --druid data source -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

        <! --mybatis-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>

        <! -- Spring-security implements password encryption -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
            <version>2.1.6. RELEASE</version>
        </dependency>

        <! --fastjsoon-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
Copy the code

3. Create SpringbootEncryptionApplication start

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@SpringBootApplication
@MapperScan("com.jgsu.mapper")
public class SpringbootEncryptionApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootEncryptionApplication.class, args);
    }


    /** * Add the encryption utility class to the IOC container for easy encryption ** /
    @Bean
    public BCryptPasswordEncoder encoder(a) {
        return newBCryptPasswordEncoder(); }}Copy the code

4. The entity class

There is only the username and password (the rest of the data is self-extensible)

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
    @TableId(value = "id",type = IdType.AUTO)
    private int id;
    private String username;
    private String password;
}
Copy the code

5. Service layer

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jgsu.entity.User;
import com.jgsu.exception.DataAddException;
import com.jgsu.exception.DataMatchException;
import com.jgsu.mapper.UserMapper;
import com.jgsu.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserMapper userMapper;
    // Data encryption has been injected into the IOC container in the startup class
    @Autowired
    private BCryptPasswordEncoder encoder;

    @Override
    public User userLogin(String username,String password) {
        // mybatis-plus conditional constructor, which implements according to username query
        QueryWrapper<User> wrapper = new QueryWrapper<User>();
        wrapper.eq("username", username);
        User userLogin = userMapper.selectOne(wrapper);
 
        /** * encoder. Matches (password, userlogin.getPassword ()), matches the entered password to the * line in the database. If the match is successful, the matching data is returned to the controller layer. * Why no salt, no decryption? This is already wrapped by CryptPasswordEncoder, * decrypted in encoder.matches(), so you don't need to match the password passed in to the database with the encrypted password. * * * /
        if(userLogin ! =null && encoder.matches(password, userLogin.getPassword())) {
            log.info("User {}, login successful",username);
            return userLogin;
        } else {
            log.error("Wrong username or password");
            throw new DataMatchException("405"."Wrong username or password"); }}@Override
    public User userRegister(String username, String password) {
        User user = new User();
        user.setId(user.getId());
        user.setUsername(username);
        user.setPassword(encoder.encode(password));
       int i = userMapper.insert(user);
       if (i == 1){
           log.info("User {} registered successfully",username);
           return user;
       }else {
           log.error("Registration failed due to server exception");
           throw new DataAddException("403"."Registration failed"); }}}Copy the code

6. Mapper layer

If you do not know, you can suggest to see the official documentation of Mybatis – Plus

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jgsu.entity.User;
import org.springframework.stereotype.Repository;

@Repository
public interface UserMapper extends BaseMapper<User> {
}
Copy the code

7. The controller layer

import com.jgsu.entity.User;
import com.jgsu.service.UserService;
import com.jgsu.utils.CommonResult;
import com.jgsu.utils.ResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    UserService userService;

    // Register, restful style
    @GetMapping("/register/{username}/{password}")
    public CommonResult register(@PathVariable("username") String username,@PathVariable("password") String password){
       User user = userService.userRegister(username, password);
        if(user ! =null) {return CommonResult.success(ResultCode.SUCCESS);
        }else {
            returnCommonResult.failed(ResultCode.FAILED); }}// Login, restful style
    @GetMapping("/login/{username}/{password}")
    public CommonResult login(@PathVariable("username") String username,@PathVariable("password") String password) {
        User userLogin = userService.userLogin(username,password);
        if(userLogin ! =null) {
            return CommonResult.success(ResultCode.SUCCESS);
        } else {
            returnCommonResult.failed(ResultCode.USERNAME_OR_PASSWORD_ERROR); }}}Copy the code

8. Configure classes (classes that return JSON data)

  • Interface to encapsulate error codes

    public interface IErrorCode {
        long getState(a);
    
        String getMessage(a);
    }
    Copy the code
  • Enumerates some common API opcodes

    public enum ResultCode implements IErrorCode {
        /** * succeeded */
        SUCCESS(200."ok"),
        /** * failed */
        FAILED(500."server error"),
    
        /** * Validation expires */
        VALIDATE_FAILED(404."undefined"),
        /**
         * 未登录
         */
        UNAUTHORIZED(401."Not logged in"),
        /** * The username or password is incorrect */
        USERNAME_OR_PASSWORD_ERROR(405."Wrong username or password"),
        /**
         * 数据查询错误
         */
        DATA_Not_Exist_ERROR(603."The data doesn't exist."),
        /**
         * 数据添加出现问题
         */
        DATA_ADD_ERROR(604."Data addition exception"),
    
        /** * file */
        FILE_ERROR(605."Error uploading file"),
        /** * Data query error */
        IMAGE_ERROR(606."Image processing error"),
        /** * Permissions are insufficient */
        FORBIDDEN(403."forbidden");
    
    
        private long state;
        private String stateInfo;
    
         ResultCode(long state, String stateInfo) {
            this.state = state;
            this.stateInfo = stateInfo;
        }
    
        @Override
        public long getState(a) {
            return state;
        }
    
        @Override
        public String getMessage(a) {
            returnstateInfo; }}Copy the code
  • Generic return object

    public class CommonResult<T> {
        private long state;
        private String stateInfo;
        private T data;
    
        public CommonResult() { } public CommonResult(long state, String stateInfo, T data) { this.state = state; this.stateInfo = stateInfo; this.data = data; } public CommonResult(long state, String stateInfo) { this.state = state; this.stateInfo = stateInfo; } public static <T> CommonResult<T> success(T data) {returnnew CommonResult<T>(ResultCode.SUCCESS.getState(), ResultCode.SUCCESS.getMessage(), data); } /** * Successfully returned result * @param data obtained data * @param message message * @return
         */
        public static <T> CommonResult<T> success(T data, String message) {
            returnnew CommonResult<T>(ResultCode.SUCCESS.getState(), message, data); */ public static <T> CommonResult<T> failed(IErrorCode errorCode) {returnnew CommonResult<T>(errorCode.getState(), errorCode.getMessage(), null); } public static <T> CommonResult<T> failed(String message) {returnnew CommonResult<T>(ResultCode.FAILED.getState(), message, null); } public static <T> CommonResult<T> failed(int code, String message) {returnfailed(ResultCode.FAILED); } /** * public static <T> CommonResult<T>validateFailed() {
            returnfailed(ResultCode.VALIDATE_FAILED); Public static <T> CommonResult<T> validateFailed(String message) {public static <T> CommonResult<T> validateFailed(String message)returnnew CommonResult<T>(ResultCode.VALIDATE_FAILED.getState(), message, null); } public static <T> CommonResult<T> unauthorized(T data) {returnnew CommonResult<T>(ResultCode.UNAUTHORIZED.getState(), ResultCode.UNAUTHORIZED.getMessage(), data); } public static <T> CommonResult<T> forbidden(T data) {return new CommonResult<T>(ResultCode.FORBIDDEN.getState(), ResultCode.FORBIDDEN.getMessage(), data);
        }
    
        public long getState() {
            return state;
        }
    
        public void setState(long state) {
            this.state = state;
        }
    
        public String getStateInfo() {
            return stateInfo;
        }
    
        public void setStateInfo(String stateInfo) {
            this.stateInfo = stateInfo;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) { this.data = data; }}Copy the code

9. Exception classes

  • Global exception interceptor class

    @Slf4j
    @ControllerAdvice
    @ResponseBody
    public class GlobalExceptionHander {
    
        @ExceptionHandler(value = Exception.class)
        public CommonResult handlerException(Exception e){
            if (e instanceof DataAddException){
                log.error(DataAddException: request method {}, request path {},((DataAddException)e).getCode(),((DataAddException)e).getMessage());
                return CommonResult.failed(ResultCode.DATA_ADD_ERROR);
            }else if (e instanceof DataMatchException){
                log.error(DataMatchException: Request method {}, request path {},((DataMatchException)e).getCode(),((DataMatchException)e).getMessage());
                return CommonResult.failed(ResultCode.USERNAME_OR_PASSWORD_ERROR);
            } else {
                log.error("Server internal error {}",e);
                returnCommonResult.failed(ResultCode.FAILED); }}}Copy the code
  • Custom data add exception classes

    public class DataAddException extends RuntimeException {
        private String code;
        private String message;
        public DataAddException(String code, String message) {
            this.code = code;
            this.message = message;
        }
    
        public String getCode(a) {
            return code;
        }
    
        public void setCode(String code) {
            this.code = code;
        }
    
        @Override
        public String getMessage(a) {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message; }}Copy the code
  • Custom data matching exception classes

    public class DataMatchException extends RuntimeException {
           private String code;
           private String message;
           public DataMatchException(String code, String message) {
               this.code = code;
               this.message = message;
           }
    
           public String getCode(a) {
               return code;
           }
    
           public void setCode(String code) {
               this.code = code;
           }
    
           @Override
           public String getMessage(a) {
               return message;
           }
    
           public void setMessage(String message) {
               this.message = message; }}Copy the code

    These are all the classes that implement this function. Of course, the classes that encrypt the password only involve the service layer and the startup class. The other classes are basic classes.