mirror of
https://github.com/RemainderTime/spring-boot-base-demo.git
synced 2026-02-23 22:50:47 +08:00
初始化项目
This commit is contained in:
13
src/main/java/cn/xf/basedemo/BaseDemoApplication.java
Normal file
13
src/main/java/cn/xf/basedemo/BaseDemoApplication.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package cn.xf.basedemo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class BaseDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BaseDemoApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
126
src/main/java/cn/xf/basedemo/common/utils/JwtTokenUtils.java
Normal file
126
src/main/java/cn/xf/basedemo/common/utils/JwtTokenUtils.java
Normal file
@@ -0,0 +1,126 @@
|
||||
package cn.xf.basedemo.common.utils;
|
||||
|
||||
import com.auth0.jwt.JWT;
|
||||
import com.auth0.jwt.JWTVerifier;
|
||||
import com.auth0.jwt.algorithms.Algorithm;
|
||||
import com.auth0.jwt.exceptions.TokenExpiredException;
|
||||
import com.auth0.jwt.interfaces.Claim;
|
||||
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Description: JwtToken
|
||||
*
|
||||
* @author rsh
|
||||
* @date 2021/9/17 2:00 下午
|
||||
*/
|
||||
@Slf4j
|
||||
public class JwtTokenUtils {
|
||||
|
||||
private String tokenSecret;
|
||||
private int tokenExpire;
|
||||
|
||||
public JwtTokenUtils(String tokenSecret, int tokenExpire) {
|
||||
this.tokenSecret = StringUtils.isNotEmpty(tokenSecret) ? tokenSecret : "remaindertime";
|
||||
this.tokenExpire = tokenExpire > 0 ? tokenExpire : 14400;
|
||||
}
|
||||
|
||||
public String getTokenSecret() {
|
||||
return tokenSecret;
|
||||
}
|
||||
|
||||
public int getTokenExpire() {
|
||||
return tokenExpire;
|
||||
}
|
||||
|
||||
private final static String USER_ID = "userId";
|
||||
|
||||
/**
|
||||
* JWT生成Token.<br/>
|
||||
* <p>
|
||||
* JWT构成: header, payload, signature
|
||||
*
|
||||
* @param userId 用户id
|
||||
*/
|
||||
public String createToken(int userId) {
|
||||
try {
|
||||
Date iatDate = new Date();
|
||||
// expire time
|
||||
// Date expiresDate = DateUtils.getByDateAfterMin(iatDate, tokenExpire);
|
||||
|
||||
// header Map
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("alg", "HS256");
|
||||
map.put("typ", "JWT");
|
||||
|
||||
// build token
|
||||
// param backups {iss:Service, aud:APP}
|
||||
String token = JWT.create().withHeader(map)
|
||||
.withClaim("iss", "ll-app-business")
|
||||
.withClaim("aud", "APP")
|
||||
.withClaim(USER_ID, String.valueOf(userId))
|
||||
.withIssuedAt(iatDate)
|
||||
// .withExpiresAt(expiresDate)
|
||||
.sign(Algorithm.HMAC256(tokenSecret));
|
||||
|
||||
return token;
|
||||
} catch (Exception e) {
|
||||
log.error("生成token异常", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密Token
|
||||
*
|
||||
* @param token
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public Map<String, Claim> verifyToken(String token) {
|
||||
if (token == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(tokenSecret)).build();
|
||||
DecodedJWT jwt = verifier.verify(token);
|
||||
return jwt.getClaims();
|
||||
} catch (Exception e) {
|
||||
if (e instanceof TokenExpiredException) {
|
||||
// token 已过期
|
||||
}
|
||||
log.error("解密Token异常", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Token获取userId
|
||||
*
|
||||
* @param token
|
||||
* @return userId
|
||||
*/
|
||||
public Integer getUserId(String token) {
|
||||
Map<String, Claim> claims = verifyToken(token);
|
||||
if (claims != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Claim claim = claims.get(USER_ID);
|
||||
if (null == claim || StringUtils.isEmpty(claim.asString())) {
|
||||
return null;
|
||||
}
|
||||
return Integer.parseInt(claim.asString());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
JwtTokenUtils jwtTokenUtils = new JwtTokenUtils("124235rfwe234", 100000);
|
||||
System.out.println(jwtTokenUtils.createToken(1));
|
||||
}
|
||||
|
||||
}
|
||||
44
src/main/java/cn/xf/basedemo/config/GlobalCorsConfig.java
Normal file
44
src/main/java/cn/xf/basedemo/config/GlobalCorsConfig.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package cn.xf.basedemo.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* Description: 全局跨域配置
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class GlobalCorsConfig {
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public FilterRegistrationBean<CorsFilter> corsFilter() {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
// 放行哪些原始域
|
||||
//config.addAllowedOrigin("*");
|
||||
// 放行哪些原始域,SpringBoot2.4.4下低版本使用.allowedOrigins("*")
|
||||
config.addAllowedOriginPattern("*");
|
||||
// 放行哪些原始请求头部信息
|
||||
config.addAllowedHeader("*");
|
||||
// 放行全部请求
|
||||
config.addAllowedMethod("*");
|
||||
// 是否发送Cookie
|
||||
config.setAllowCredentials(true);
|
||||
|
||||
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
|
||||
configSource.registerCorsConfiguration("/**", config);
|
||||
|
||||
FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(configSource));
|
||||
// 这个顺序很重要哦,为避免麻烦请设置在最前
|
||||
bean.setOrder(0);
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
23
src/main/java/cn/xf/basedemo/config/InterceptorConfig.java
Normal file
23
src/main/java/cn/xf/basedemo/config/InterceptorConfig.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package cn.xf.basedemo.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @program: spring-boot-base-demo
|
||||
* @ClassName InterceptorConfig
|
||||
* @description:
|
||||
* @author: xiongfeng
|
||||
* @create: 2022-06-16 13:59
|
||||
**/
|
||||
@Configuration
|
||||
public class InterceptorConfig implements WebMvcConfigurer {
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new TokenInterceptor()) //登录逻辑拦截类
|
||||
.addPathPatterns("/**") //需要拦截的请求(设置的全部拦截)
|
||||
.excludePathPatterns("`/user/login","/user/register`"); //忽略的请求
|
||||
}
|
||||
}
|
||||
53
src/main/java/cn/xf/basedemo/config/MybatisPlusConfig.java
Normal file
53
src/main/java/cn/xf/basedemo/config/MybatisPlusConfig.java
Normal file
@@ -0,0 +1,53 @@
|
||||
package cn.xf.basedemo.config;
|
||||
|
||||
import com.baomidou.dynamic.datasource.plugin.MasterSlaveAutoRoutingPlugin;
|
||||
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
@Configuration
|
||||
@MapperScan("cn.xf.basedemo.mappers")
|
||||
@EnableTransactionManagement
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
/**
|
||||
* 分页插件
|
||||
*
|
||||
* @return PaginationInterceptor
|
||||
*/
|
||||
@Bean
|
||||
public PaginationInterceptor paginationInterceptor() {
|
||||
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
|
||||
// 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求 默认false
|
||||
paginationInterceptor.setOverflow(false);
|
||||
// 设置最大单页限制数量,默认 500 条,-1 不受限制
|
||||
paginationInterceptor.setLimit(500);
|
||||
// 开启 count 的 join 优化,只针对部分 left join
|
||||
paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
|
||||
return paginationInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读写分离
|
||||
*
|
||||
* @return MasterSlaveAutoRoutingPlugin
|
||||
*/
|
||||
@Bean
|
||||
public MasterSlaveAutoRoutingPlugin masterSlaveAutoRoutingPlugin() {
|
||||
return new MasterSlaveAutoRoutingPlugin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 乐观锁插件
|
||||
*
|
||||
* @return OptimisticLockerInterceptor
|
||||
*/
|
||||
@Bean
|
||||
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
|
||||
return new OptimisticLockerInterceptor();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package cn.xf.basedemo.config;
|
||||
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
|
||||
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
|
||||
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.web.*;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
|
||||
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import springfox.documentation.builders.ApiInfoBuilder;
|
||||
import springfox.documentation.builders.PathSelectors;
|
||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
||||
import springfox.documentation.oas.annotations.EnableOpenApi;
|
||||
import springfox.documentation.service.ApiInfo;
|
||||
import springfox.documentation.service.Contact;
|
||||
import springfox.documentation.spi.DocumentationType;
|
||||
import springfox.documentation.spring.web.plugins.Docket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @program: spring-boot-base-demo
|
||||
* @ClassName SpringFoxSwaggerConfig
|
||||
* @description:
|
||||
* @author: xiongfeng
|
||||
* @create: 2022-06-16 16:44
|
||||
**/
|
||||
@EnableOpenApi
|
||||
@Configuration
|
||||
public class SpringFoxSwaggerConfig {
|
||||
|
||||
/**
|
||||
* 配置基本信息
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.title("Swagger Test App Restful API")
|
||||
.description("swagger test app restful api")
|
||||
.termsOfServiceUrl("https://github.com/RemainderTime")
|
||||
.contact(new Contact("君燕尾","https://blog.csdn.net/qq_39818325","fairy_xingyun@hotmail.com"))
|
||||
.version("1.0")
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置文档生成最佳实践
|
||||
* @param apiInfo
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public Docket createRestApi(ApiInfo apiInfo) {
|
||||
return new Docket(DocumentationType.OAS_30)
|
||||
.apiInfo(apiInfo)
|
||||
.groupName("SwaggerGroupOneAPI")
|
||||
.select()
|
||||
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
|
||||
.paths(PathSelectors.any())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加如下配置可解决Spring Boot 6.x 与Swagger 3.0.0 不兼容问题
|
||||
**/
|
||||
@Bean
|
||||
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier, ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties, Environment environment) {
|
||||
List<ExposableEndpoint<?>> allEndpoints = new ArrayList();
|
||||
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
|
||||
allEndpoints.addAll(webEndpoints);
|
||||
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
|
||||
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
|
||||
String basePath = webEndpointProperties.getBasePath();
|
||||
EndpointMapping endpointMapping = new EndpointMapping(basePath);
|
||||
boolean shouldRegisterLinksMapping = this.shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
|
||||
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath), shouldRegisterLinksMapping, null);
|
||||
}
|
||||
private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment, String basePath) {
|
||||
return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
|
||||
}
|
||||
}
|
||||
34
src/main/java/cn/xf/basedemo/config/TokenInterceptor.java
Normal file
34
src/main/java/cn/xf/basedemo/config/TokenInterceptor.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package cn.xf.basedemo.config;
|
||||
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* @program: spring-boot-base-demo
|
||||
* @ClassName TokenInterceptor
|
||||
* @description:
|
||||
* @author: xiongfeng
|
||||
* @create: 2022-06-16 14:17
|
||||
**/
|
||||
public class TokenInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
|
||||
String requestURI = request.getRequestURI();
|
||||
|
||||
//登录处理
|
||||
String authorization = request.getHeader("Authorization");
|
||||
|
||||
|
||||
return HandlerInterceptor.super.preHandle(request, response, handler);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user