- 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.