数据统一格式
@ApiModel(value = "返回结果集的实体")
public class R {
@ApiModelProperty("code值 0:表示成功 非0:表示失败")
private Integer code; //返回的响应码
@ApiModelProperty("出错之后的错误的提示信息")
private String msg; //错误的提示信息
@ApiModelProperty("请求成功之后向客户端返回数据")
private HashMap<String,Object> data=new HashMap<>(); //客户端请求服务端的返回数据,可以直接继承
private R(){}
/**
* 这个表示的是请求成功
* @return
*/
public static R ok(){
R r = new R();
r.setCode(ResponceCode.SUCCESS.getCode());
r.setMsg(ResponceCode.SUCCESS.getmsg());
return r;
}
/**
* 请求失败的封装
* @return
*/
public static R error(){
R r = new R();
r.setCode(ResponceCode.ERROR.getCode());
r.setMsg(ResponceCode.ERROR.getmsg());
return r;
}
/**
* 向返回数据中添加键值对
* @param key
* @param val
* @return
*/
public R data(String key,Object val){
this.data.put(key,val);
return this;
}
/**
* 向返回数据中添加键值对
* @param map
* @return
*/
public R data(HashMap<String,Object> map){
Set<Map.Entry<String, Object>> entries = map.entrySet();
Iterator<Map.Entry<String, Object>> it = entries.iterator();
while (it.hasNext()){
Map.Entry<String, Object> next = it.next();
String key = next.getKey();
Object value = next.getValue();
//放进原来的集合中
this.data.put(key,value);
}
return this;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public HashMap<String, Object> getData() {
return data;
}
public void setData(HashMap<String, Object> data) {
this.data = data;
}
}
枚举类
/**
* @description: 响应的状态码的枚举:把可能出错的状态吗和错误信息 全部封装到这里来
*
* 1、枚举是单例还是多例?
* 每一个枚举项都是一个单例 整个的枚举这个类 是天生的多例
*
* 2、枚举是否可以有成员变量?
* 枚举就是一个类 是类 就意味着这个类 可以有成员变量
* 枚举是否可以有方法呢? 枚举是类 是类 就意味着 一定可以有方法
*
* 3、枚举是否可以有构造器?
* 枚举是类 类 就一定可以有构造器
*
*/
public enum ResponceCode {
SUCCESS(0,"请求成功"),
ERROR(-1,"请求失败"),
SYSTEM_EXCEPTION(100,"系统异常"),
SQL_EXCEPTION(101,"SQL语句异常"),
PARAMETER_EXCEPTION(102,"参数有误");
//......
private Integer code; //状态码
private String msg; //错误的提示信息
ResponceCode(Integer code,String msg){
this.code=code;
this.msg=msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getmsg() {
return msg;
}
public void setmsg(String msg) {
this.msg = msg;
}
}
MD5工具类
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class MD5Util {
public static String getMD5Password(String pwd){
StringBuilder hexString = new StringBuilder();
try {
// 创建MD5消息摘要对象
MessageDigest md = MessageDigest.getInstance("MD5");
// 计算MD5哈希值
byte[] hash = md.digest(pwd.getBytes());
// 转换为十六进制字符串
for (byte b : hash) {
String hex = Integer.toHexString(0xFF & b);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
System.out.println("MD5 Hash: " + hexString.toString());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return hexString.toString();
}
/**
* 测试md5的值
*/
// public static void main(String[] args) {
// final String md5Password = getMD5Password("12543");
// System.out.println(md5Password);
// }
}
JWT工具类
public class JWTUtil {
//有效期为30分钟
private static final long EXPIRATION_TIME =24*60 * 60 * 1000;
//服务端的秘钥,切记保密,而且注意周期更换
//采用非对称加密方式更好
private static final String SECRET = "http://www.zx_class.com";
/**
* 生成token
* @param user
* @return
*/
public static String generateToken(User user){
Map<String,Object> map = new HashMap<>();
map.put("userId",user.getId());
map.put("username",user.getName());
Algorithm algorithm = Algorithm.HMAC256(SECRET);
//租约到期时间
Long expireTime = new Date().getTime() + EXPIRATION_TIME;
SimpleDateFormat sdf = new SimpleDateFormat();
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(expireTime);
Date time = calendar.getTime();
String token = JWT.create()
.withPayload(map)
.withExpiresAt(time)
.sign(algorithm);
return token;
}
/**
* 解析token
* @param token
*/
public static Map<String,Claim> parseToken(String token) {
Algorithm algorithm = Algorithm.HMAC256(SECRET);
JWTVerifier verifier = JWT.require(algorithm)
.build(); //Reusable verifier instance
DecodedJWT jwt = verifier.verify(token);
Map<String, Claim> claims = jwt.getClaims();
return claims;
}
/**
* 获取token中的信息
* @param token
* @return 仅仅将用户id 用户名称
*/
public static User getUserInfo(String token){
Map<String, Claim> map = parseToken(token);
Claim claim = map.get("userId");
Claim name = map.get("username");
Integer userId = claim.asInt();
User user = new User();
user.setId(userId.intValue());
user.setName(name.asString());
return user;
}
/**
* 测试代码,可以不理会
* @param args
*/
public static void main(String[] args) {
User user = new User();
user.setId(18);
user.setName("xxxxx");
String token = generateToken(user);
System.out.println(token);
User userInfo = getUserInfo(token);
System.out.println(userInfo.toString());
}
}
JWT maven
<!-- TODO JWT依赖相关 -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
Guava本地缓存
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class BaseCache {
// 根据时间过期
private Cache<String,Object> tenMinuteCache = CacheBuilder.newBuilder()
//设置缓存初始大小,设置要合理,根据项目需求来,可以扩容
.initialCapacity(10)
//最大值
.maximumSize(100)
//并发数设置
.concurrencyLevel(5)
//缓存过期时间
.expireAfterWrite(10, TimeUnit.SECONDS)
//统计缓存命中率
.recordStats()
.build();
private Cache<String,Object> oneHourCache = CacheBuilder.newBuilder()
//设置缓存初始大小,设置要合理,根据项目需求来,可以扩容
.initialCapacity(30)
//最大值
.maximumSize(100)
//并发数设置
.concurrencyLevel(5)
//缓存过期时间
.expireAfterWrite(3600, TimeUnit.SECONDS)
//统计缓存命中率
.recordStats()
.build();
public Cache<String, Object> getTenMinuteCache() {
return tenMinuteCache;
}
public void setTenMinuteCache(Cache<String, Object> tenMinuteCache) {
this.tenMinuteCache = tenMinuteCache;
}
public Cache<String, Object> getOneHourCache() {
return oneHourCache;
}
public void setOneHourCache(Cache<String, Object> oneHourCache) {
this.oneHourCache = oneHourCache;
}
}
全局异常处理
@RestControllerAdvice
public class GlobalException {
@ExceptionHandler(Throwable.class)
public R handler(Throwable e){
return R.error().data("errorMsg",e.getMessage());
}
}
SpringBoot(2.7.13) 的WebMvcConfigurer配置
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurationSupport {
/**
* 静态资源的拦截
* 发现如果继承了WebMvcConfigurationSupport,
* 则在yml中配置的相关内容会失效。 需要重新指定静态资源
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**").addResourceLocations(
"classpath:/static/");
registry.addResourceHandler("swagger-ui.html", "doc.html").addResourceLocations(
"classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations(
"classpath:/META-INF/resources/webjars/");
super.addResourceHandlers(registry);
}
// @Bean
// TokenInterceptor tokenInterceptor(){
// return new TokenInterceptor();
// }
//
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(tokenInterceptor()).addPathPatterns("api/user/*/**")
// .excludePathPatterns("/api/user/register","/api/user/login","/api/pub/**");
// super.addInterceptors(registry);
// }
}
Swagger2配置
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@SpringBootConfiguration
@EnableSwagger2 //开启swagger
public class SwaggerConfig {
/* * swagger会帮助我们生成接口文档
* 1:配置生成的文档信息:比如文档名称、作者、版本..
* 2: 配置生成规则
* /
/*Docket封装接口文档信息*/
@Bean
public Docket getDocket() {
//创建封面信息对象
ApiInfoBuilder apiInfoBuilder = new ApiInfoBuilder();
apiInfoBuilder.title("在线课程") //文档标题
.description("在线课程") //文档说明
.version("v 1.0.0") //版本
.contact(new Contact("pan", "", "1827675843@qq.com"));//作者
ApiInfo apiInfo = apiInfoBuilder.build();
//DocumentationType.SWAGGER_2:指定文档风格
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo) //指定生成的文档中的封面信息:文档标题、版本、作者
.select()
.apis(RequestHandlerSelectors.basePackage("com.online_class.controller")) //为指定包的处理器方法生成接口文档
//.paths(PathSelectors.regex("/user/"))//指定com.wudagai.neumall.controller中/user/的路径
.paths(PathSelectors.any()) //指定中所有的路径
.build();
return docket;
}
}
拦截器配置示例(具体自己更改)
import com.online_class.interceptor.TokenInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@Configuration
public class InterceptorConfig extends WebMvcConfigurer {
@Bean
TokenInterceptor tokenInterceptor(){
return new TokenInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(tokenInterceptor()).addPathPatterns("api/user/*/**")
.excludePathPatterns("/api/user/register","/api/user/login","/api/pub/**");
InterceptorConfig.super.addInterceptors(registry);
}
}
常用dependency坐标(2.7.13)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.7.13</version>
</dependency>
<!-- TODO mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
</dependency>
<!-- TODO JWT依赖相关 -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<!---->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1-jre</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version> 2.9.2</version>
</dependency>
<!-- swagger-ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<!-- 美化swagger -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
</dependencies>
mybatis—yml文件配置
server:
port: 8081
spring:
datasource:
username: ****
password: ******
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/online_class?useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai
type: com.alibaba.druid.pool.DruidDataSource
mvc:
pathmatch:
matching-strategy: ANT_PATH_MATCHER
mybatis:
type-aliases-package: com.online_class.domain
configuration:
map-underscore-to-camel-case: true
mapper-locations: classpath*:mapper/*.xml
mybatis模板
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.online_class.mapper.ChapterMapper">
<!-- <resultMap id="ChapterResultMap" type="Chapter">-->
<!-- <id column="id" property="id" />-->
<!-- <result column="video_id" property="videoId" />-->
<!-- <result column="title" property="title" />-->
<!-- <result column="ordered" property="ordered" />-->
<!-- <result column="create_time" property="createTime" />-->
<!-- <collection property="episodeList" ofType="Episode">-->
<!-- <id property="id" column="episode_id"/>-->
<!-- <result property="title" column="title" />-->
<!-- <result property="num" column="num" />-->
<!-- <result column="ordered" property="ordered" />-->
<!-- <result property="playUrl" column="play_url" />-->
<!-- <result property="chapterId" column="chapter_id"/>-->
<!-- <result property="free" column="free"/>-->
<!-- <result property="createTime" column="create_time"/>-->
<!-- </collection>-->
<!-- </resultMap>-->
<!-- <select id="findAllChapter" resultMap="ChapterResultMap">-->
<!-- select *-->
<!-- from Chapter-->
<!-- WHERE id=#{id}-->
<!-- ORDER BY-->
<!-- </select>-->
</mapper>