1.Swagger UI展示接口文档
2.RedisCache缓存查询结果,减轻查询数据库压力
3.接口调用使用Token认证
Win10
Spring Boot v2.7.1
Springfox-swagger2 2.9.2
Springfox-swagger-ui 2.9.2
Java-jwt 3.8.3
项目根目录下的pom.xml
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.7.1-SNAPSHOTversion>
<relativePath/>
parent>
<groupId>com.examplegroupId>
<artifactId>demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>demoname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger-uiartifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>com.auth0groupId>
<artifactId>java-jwtartifactId>
<version>3.8.3version>
dependency>
<dependency>
<groupId>com.vaadin.external.googlegroupId>
<artifactId>android-jsonartifactId>
<version>0.0.20131108.vaadin1version>
<scope>compilescope>
dependency>
<dependency>
<groupId>net.sf.json-libgroupId>
<artifactId>json-libartifactId>
<version>2.2.3version>
<classifier>jdk15classifier>
<exclusions>
<exclusion>
<artifactId>ezmorphartifactId>
<groupId>net.sf.ezmorphgroupId>
exclusion>
<exclusion>
<artifactId>commons-beanutilsartifactId>
<groupId>commons-beanutilsgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelper-spring-boot-starterartifactId>
<version>1.4.1version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjrtartifactId>
<version>1.8.8version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.8.8version>
dependency>
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiter-apiartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-cacheartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>1.9.4version>
dependency>
<dependency>
<groupId>commons-httpclientgroupId>
<artifactId>commons-httpclientartifactId>
<version>3.1version>
dependency>
<dependency>
<groupId>net.sf.ezmorphgroupId>
<artifactId>ezmorphartifactId>
<version>1.0.6version>
dependency>
dependencies>
<build>
<defaultGoal>compiledefaultGoal>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
<repositories>
<repository>
<id>spring-milestonesid>
<name>Spring Milestonesname>
<url>https://repo.spring.io/milestoneurl>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
<repository>
<id>spring-snapshotsid>
<name>Spring Snapshotsname>
<url>https://repo.spring.io/snapshoturl>
<releases>
<enabled>falseenabled>
releases>
repository>
repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestonesid>
<name>Spring Milestonesname>
<url>https://repo.spring.io/milestoneurl>
<snapshots>
<enabled>falseenabled>
snapshots>
pluginRepository>
<pluginRepository>
<id>spring-snapshotsid>
<name>Spring Snapshotsname>
<url>https://repo.spring.io/snapshoturl>
<releases>
<enabled>falseenabled>
releases>
pluginRepository>
pluginRepositories>
project>
添加这几个依赖,解决JSONObject报错
以下实体模型均实现了Serializable 序列化接口
用户模型:UserDomain.java
package com.example.demo.domain;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.io.Serializable;
/**
* 用户实体模型,提供属性赋值和获取
*/
public class UserDomain implements Serializable{
private Integer id;
private String user;
private String password;
public String getId(){
return id.toString();
}
public void setId(String id){
this.id=Integer.valueOf(id);
}
public String getUser(){
return user;
}
public void setUser(String user){
this.user=user;
}
public String getPassword(){
return password;
}
public void setPassword(String password){
this.password=password;
}
/**
* @param password 明文密码
* 将加密后的密文赋值到实体属性
*/
public void setEncodePassword(String password) {
BCryptPasswordEncoder bCryptPasswordEncoder=new BCryptPasswordEncoder();
this.password = bCryptPasswordEncoder.encode(password);
}
/**
* @param rawPassword 明文密码
* @return 校验结果
*/
public boolean checkPassword(String rawPassword){
BCryptPasswordEncoder bCryptPasswordEncoder=new BCryptPasswordEncoder();
return bCryptPasswordEncoder.matches(rawPassword,password);
}
}
成绩模型:ScoreDomain.java
package com.example.demo.domain;
import java.io.Serializable;
/**
* 成绩实体模型
*/
public class ScoreDomain implements Serializable {
private Integer id;
private String sid;
private float score;
public String getId(){
return id.toString();
}
public void setId(String id){
this.id=Integer.valueOf(id);
}
public String getSid(){
return sid;
}
public void setSid(String sid){
this.sid=sid;
}
public String getScore(){
return String.valueOf(score);
}
public void setScore(String score){
this.score=Float.parseFloat(score);
}
}
将SQL语句和实体模型绑定,实现字段赋值和查询
ScoreMapper接口
package com.example.demo.mapper;
import com.example.demo.domain.ScoreDomain;
import org.apache.ibatis.annotations.*;
import java.util.List;
//import org.apache.tomcat.jni.User;
/**
* 将模型与SQL绑定,实现增删改查
*/
@Mapper
public interface ScoreMapper {
@Select("select * from sc where id=#{id}")
ScoreDomain getScoreById(Integer id);
@Insert("insert into sc(sid,score) values(#{sid},#{score})")
int insert(ScoreDomain score);
@Update("update sc set sid=#{sid},score=#{score} where id=#{id}")
int update(ScoreDomain score);
@Delete("delete from sc where id=#{id}")
int delete(Integer id);
@Select("select * from sc")
List<ScoreDomain> list();
}
UserMapper接口
package com.example.demo.mapper;
import com.example.demo.domain.UserDomain;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* 将模型与SQL绑定,实现增删改查
*/
@Mapper
public interface UserMapper {
@Select("select * from user where id=#{id}")
UserDomain getUserById(Integer id);
@Select("select * from user where user=#{user}")
UserDomain getUserByUser(String user);
@Insert("insert into user (user,password) values(#{user},#{password})")
int insert(UserDomain userDomain);
@Update("update user set user=#{user},password=#{password} where id=#{id}")
int update(UserDomain userDomain);
@Delete("delete from user where id=#{id}")
int delete(Integer id);
@Select("select * from user")
List<UserDomain> list();
}
创建接口ScoreInterface.java,规范Service实现类
package com.example.demo.service;
import com.example.demo.domain.ScoreDomain;
import java.util.List;
public interface ScoreInterface {
int insert(ScoreDomain scoredomain);
int update(ScoreDomain scoredomain);
int delete(String id);
ScoreDomain get(String id);
List<ScoreDomain> list(String page,String limit);
}
创建成绩的Service实现类ScoreService.java
package com.example.demo.service;
import com.example.demo.domain.ScoreDomain;
import com.example.demo.mapper.ScoreMapper;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 调用Mapper,实现成绩模型增删改查
*/
@Service
public class ScoreService implements ScoreInterface {
@Autowired
private ScoreMapper scoremapper;
@Override
public int insert(ScoreDomain scoredomain) {
return scoremapper.insert(scoredomain);
}
@Override
public int update(ScoreDomain scoredomain) {
return scoremapper.update(scoredomain);
}
@Override
public int delete(String id) {
return scoremapper.delete(Integer.valueOf(id));
}
@Override
public ScoreDomain get(String id) {
return scoremapper.getScoreById(Integer.valueOf(id));
}
@Override
public List<ScoreDomain> list(String page,String limit) {
PageHelper.startPage(Integer.parseInt(page),Integer.parseInt(limit)); //开启分页,必须放在查询语句前
return scoremapper.list();
}
}
创建接口UserInterface.java,规范Service实现类
package com.example.demo.service;
import com.example.demo.domain.UserDomain;
import java.util.List;
public interface UserInterface {
UserDomain getUserById(String id);
UserDomain getUserByUser(String user);
Object insert(UserDomain userDomain);
int update(UserDomain userDomain);
int delete(String id);
List<UserDomain> list(String page, String limit);
}
创建用户的Service实现类UserService.java
package com.example.demo.service;
import com.example.demo.domain.UserDomain;
import com.example.demo.mapper.UserMapper;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 运用Mapper实现用户模型查询
*/
@Service
public class UserService implements UserInterface {
@Autowired
private UserMapper userMapper;
/**
* @param id 主键id
* @return 用户实体
* 根据主键id查询用户实体
*/
@Override
public UserDomain getUserById(String id) {
return userMapper.getUserById(Integer.valueOf(id));
}
/**
* @param user 主键user
* @return 用户实体
* 根据主键user查询用户实体
*/
@Override
public UserDomain getUserByUser(String user) {
return userMapper.getUserByUser(user);
}
/**
* @param userDomain 用户实体
* @return 序列化后的用户实体
*/
@Override
public Object insert(UserDomain userDomain) {
if (userMapper.getUserByUser(userDomain.getUser()) != null) {
return new ResponseEntity<>(HttpStatus.CREATED);
}
if (userMapper.insert(userDomain) == 1) {
return userMapper.getUserByUser(userDomain.getUser());
} else {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
/**
* @param userDomain 用户实体
* @return 更新结果条数
*/
@Override
public int update(UserDomain userDomain) {
return userMapper.update(userDomain);
}
@Override
public int delete(String id) {
return userMapper.delete(Integer.valueOf(id));
}
/**
* @param page 页码
* @param limit 每页内容数量
* @return 用户实体列表
*/
@Override
public List<UserDomain> list(String page, String limit) {
PageHelper.startPage(Integer.parseInt(page), Integer.parseInt(limit)); //开启分页,必须放在查询语句前
return userMapper.list();
}
}
创建UserController.java
package com.example.demo.controller;
import com.example.demo.annotation.LoginToken;
import com.example.demo.domain.ScoreDomain;
import com.example.demo.domain.UserDomain;
import com.example.demo.service.UserService;
import com.example.demo.util.GetCheckToken;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@CacheConfig(cacheNames = "UserController") //设置Redis中key的前缀
@RestController
public class UserController {
@Autowired
UserService userService;
@Autowired
GetCheckToken tokenService;
//登录
//覆盖注入配置
@ApiImplicitParams({
@ApiImplicitParam(name = "token", value = "非必须token", required = false, dataType = "String", paramType = "header")})
@PostMapping("/login")
public Object login(@RequestBody Map<String,String> params) {
JSONObject jsonObject = new JSONObject();
UserDomain userDomain = userService.getUserByUser(params.get("user"));
if (userDomain == null) {
jsonObject.put("message", "登录失败,用户不存在"); //在正式环境中不应该提示用户不存在
return jsonObject;
} else {
if (! userDomain.checkPassword(params.get("password"))) {
jsonObject.put("message", "登录失败,密码错误");
return jsonObject;
} else {
String token = tokenService.getToken(userDomain);
jsonObject.put("token", token); //用户验证合法后发放token
// jsonObject.put("user", userDomain);
return jsonObject;
}
}
}
@ApiImplicitParams({
@ApiImplicitParam(name = "token", value = "非必须token", required = false, dataType = "String", paramType = "header")})
@PostMapping("/register")
public Object register(@RequestBody Map<String,String> params) {
UserDomain userDomain = new UserDomain();
userDomain.setUser(params.get("user"));
userDomain.setEncodePassword(params.get("password"));
return userService.insert(userDomain);
}
@LoginToken
@ApiOperation(value = "用户列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "页码", required = false, dataType = "String"),
@ApiImplicitParam(name = "limit", value = "每页内容数量", required = false, dataType = "String")})
@GetMapping("/users")
@Cacheable(keyGenerator = "selfKeyGenerate") //添加此注解可缓存查询结果
public List<UserDomain> list(@RequestParam("page") String page, @RequestParam("limit") String limit) {
return userService.list(page, limit);
}
@LoginToken
@ApiOperation(value = "获取单个用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "主键", required = true, dataType = "String"),
})
@GetMapping("/users/{id}")
public UserDomain getObject(@PathVariable String id) {
return userService.getUserById(id);
}
@LoginToken
@ApiOperation(value = "修改用户")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "主键", required = true, dataType = "String")
})
@PutMapping("/users/{id}")
public int updateObject(@RequestBody Map<String,String> params,@PathVariable String id) {
UserDomain userDomain = new UserDomain();
userDomain.setUser(params.get("user"));
userDomain.setId(id);
userDomain.setEncodePassword(params.get("password"));
return userService.update(userDomain);
}
@LoginToken
@ApiOperation(value = "删除用户")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键", required = true, dataType = "String"),
})
@DeleteMapping("/users/{id}")
public int deleteObject(@PathVariable String id) {
return userService.delete(id);
}
}
创建ScoreController.java
package com.example.demo.controller;
import com.example.demo.annotation.LoginToken;
import com.example.demo.domain.ScoreDomain;
import com.example.demo.service.ScoreService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@Api
@RestController
@CacheConfig(cacheNames = "ScoreController") //设置Redis中key的前缀
@Component
public class ScoreController {
@Autowired
private ScoreService scoreService;
@LoginToken
@ApiOperation(value = "成绩列表")
@ApiImplicitParams({@ApiImplicitParam(name = "page", value = "页码", required = false, dataType = "String"),
@ApiImplicitParam(name = "limit", value = "每页内容数量", required = false, dataType = "String")})
@GetMapping("/scores")
@Cacheable(keyGenerator = "selfKeyGenerate") //添加此注解可缓存查询结果
public List<ScoreDomain> list(@RequestParam("page") String page, @RequestParam("limit") String limit) {
return scoreService.list(page, limit);
}
@LoginToken
@ApiOperation(value = "添加成绩")
@PostMapping("/scores")
public int create(@RequestBody Map<String, String> params) {
ScoreDomain scoreDomain = new ScoreDomain();
scoreDomain.setSid(params.get("sid"));
scoreDomain.setScore(params.get("score"));
return scoreService.insert(scoreDomain);
}
@LoginToken
@ApiOperation(value = "获取成绩")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键", required = true, dataType = "String"),
})
@GetMapping("/scores/{id}")
public ScoreDomain getObject(@PathVariable String id) {
return scoreService.get(id);
}
@LoginToken
@ApiOperation(value = "修改成绩")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键", required = true, dataType = "String")
})
@PutMapping("/scores/{id}")
public int updateObject(@RequestBody Map<String, String> params, @PathVariable String id) {
ScoreDomain scoreDomain = new ScoreDomain();
scoreDomain.setId(id);
scoreDomain.setSid(params.get("sid"));
scoreDomain.setScore(params.get("score"));
return scoreService.update(scoreDomain);
}
@LoginToken
@ApiOperation(value = "删除成绩")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "主键", required = true, dataType = "String"),
})
@DeleteMapping("/scores/{id}")
public int deleteObject(@PathVariable String id) {
return scoreService.delete(id);
}
}
创建SelfKeyGenerate.java
package com.example.demo.util;
import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
@Component()
public class SelfKeyGenerate implements KeyGenerator {
@Autowired
private HttpServletRequest httpServletRequest;
@Override
public Object generate(Object target, Method method, Object... params) {
String[] stringArray = new String[params.length];
for (int i = 0; i < params.length; i++) {
stringArray[i] = params[i].toString();
// stringBuilder.append(',');
}
CharSequence stringParams = StringUtil.join(",", Arrays.asList(stringArray));
String key = String.format("%s#%s(%s[%s])", target.getClass().getSimpleName(), method.getName(), httpServletRequest.getServletPath(), stringParams);
return key;
}
}
路径:
创建GetCheckToken.java类,封装token的获取和校验
package com.example.demo.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.example.demo.domain.UserDomain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Date;
@Service
@ApiModel
public class GetCheckToken {
@ApiModelProperty("盐")
private static final String SALT_KEY = "links";
@ApiModelProperty("令牌有效期毫秒")
private static final long TOKEN_VALIDITY = 86400000;
@ApiModelProperty("签发主体")
private static final String ISSUER = "alibaba";
@ApiModelProperty("Base64 密钥")
private final static String SECRET_KEY = Base64.getEncoder().encodeToString(SALT_KEY.getBytes(StandardCharsets.UTF_8)); //加盐的秘钥
/**
* 在请求API时检查token的有无和合法性
*/
public void checkToken(String token) {
if (token == null) {
throw new RuntimeException("无token,请重新登录");
}
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("401");
}
}
/**
* 1.根据主题,签发主体,签发时间,过期时间,以及加盐的秘钥生成token
*/
public String getToken(UserDomain userDomain) {
Date validity = new Date((new Date()).getTime() + TOKEN_VALIDITY);
return JWT.create().withSubject(userDomain.getId()).withIssuer(ISSUER).withExpiresAt(validity).withIssuedAt(new Date()).sign(Algorithm.HMAC256(SECRET_KEY));
}
}
路径:
创建AuthenticationInterceptor.java拦截器,拦截需要校验token的API请求
package com.example.demo.util;
import com.example.demo.annotation.LoginToken;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* 1.对LoginToken注解的API拦截校验token
*/
@Component
public class AuthenticationInterceptor implements HandlerInterceptor {
@Resource
private GetCheckToken getCheckToken;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
// 如果不是映射到方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod();
//检查有没有需要用户权限的注解
if (method.isAnnotationPresent(LoginToken.class)) {
LoginToken userLoginToken = method.getAnnotation(LoginToken.class);
if (userLoginToken.required()) {
// 执行认证
getCheckToken.checkToken(token);
}
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Object o, Exception e) throws Exception {
}
}
路径:
创建InterceptorConfig.java, 将身份认证拦截器注册到配置中
package com.example.demo.config;
import com.example.demo.util.AuthenticationInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration //此注解将此配置注册到配置中
public class InterceptorConfig implements WebMvcConfigurer {
@Resource
private AuthenticationInterceptor authenticationInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor)
.addPathPatterns("/**"); // 拦截所有请求判断有无需要校验token的注解
}
}
路径:
定义注解LoginToken.java
package com.example.demo.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginToken {
boolean required() default true;
}
创建PageHelperConfig.java,将配置注入
package com.example.demo.config;
import com.github.pagehelper.PageHelper;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
@Configuration
public class PageHelperConfig {
public PageHelper getPageHelper() {
PageHelper pageHelper = new PageHelper();
Properties properties = new Properties();
properties.setProperty("helperDialect", "mysql");
properties.setProperty("reasonable", "true");
properties.setProperty("supportMethodsArguments", "true");
properties.setProperty("params", "count=countSql");
pageHelper.setProperties(properties);
return pageHelper;
}
}
定义SwaggerConfig.java注入配置
package com.example.demo.config;
import io.swagger.annotations.Api;
//import io.swagger.annotations.Contact;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
/**
* 给每个API设置必要请求头token,登录的API不应该设置,已在LoginController.java做了覆盖处理
*/
@Bean
List<Parameter> setHeaderToken() {
List<Parameter> pars = new ArrayList<>();
ParameterBuilder parameterBuilder = new ParameterBuilder();
parameterBuilder.name("token").description("用户TOKEN").modelRef(new ModelRef("string")).parameterType("header")
.required(true).build();
pars.add(parameterBuilder.build());
return pars;
}
@Bean
public Docket getDocket() {
// 创建封面信息对象
ApiInfoBuilder apiInfoBuilder = new ApiInfoBuilder();
// 设置文档标题、描述、联系人
apiInfoBuilder.title("平台接口说明文档")
.description("此文档说明了平台后端接口规范")
.version("v1.0.0")
.contact(new Contact("CHEN", "http://127.0.0.1:8080/scores", "[email protected]"));
ApiInfo apiInfo = apiInfoBuilder.build();
// 指定文档风格
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo) // 指定生成的文档中的封面信息;文档标题、版本、作者
.select()
.apis(RequestHandlerSelectors.basePackage("com.example.demo.controller"))
.paths(PathSelectors.any())
.build().globalOperationParameters(setHeaderToken());
return docket;
}
}
项目配置application.properties
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://192.168.8.140:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER
#redis连接配置
spring.redis.host=192.168.8.140
spring.redis.port=6379
spring.redis.database=0
spring.redis.password=
#spring.redis.
spring.redis.jedis.pool.max-active=8
spring.redis.jedis.pool.max-wait=-1
spring.redis.jedis.pool.max-idle=8
spring.redis.jedis.pool.min-idle=0
spring.redis.timeout=5000
@SpringBootApplication(exclude= {SecurityAutoConfiguration.class})是为了暂时停用Spring Security认证
@EnableSwagger2 启用Swagger UI
@EnableCaching 启动缓存
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
//@Import(AuthenticationInterceptor.class)
@SpringBootApplication(exclude= {SecurityAutoConfiguration.class })
@EnableSwagger2
@EnableAspectJAutoProxy(proxyTargetClass=true)
@EnableCaching
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
库:test
表结构:user
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user` varchar(10) NOT NULL,
`password` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`,`user`),
UNIQUE KEY `user_index` (`user`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
表结构:sc
CREATE TABLE `sc` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sid` varchar(10) DEFAULT NULL,
`score` float(5,0) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
此/register接口不需要token认证
此/login接口不需要token认证
POST请求添加成绩API
DELETE请求删除成绩API
GET请求/scores接口
Redis会将请求结果以每个API所属的"Controller名称::Controller名称#list(接口PATH[page,limit])"的格式为key存储在Redis中,当请求参数一致时,将直接从Redis返回数据,如下图
以下界面是Redis的官方客户端RedisInsight-v2
上图Redis就是缓存的下图
手动在数据库修改主键值为3的数据
再次GET请求/scores接口,数据没变化
在Redis中删除对应键值数据
再次GET请求/scores接口,结果如下,说明Redis缓存失效了,直接从数据库读取了数据。