声明: 这里加密解密只是简单使用了一个base64操作的,主要是提供功能案例,具体的根据需要改
maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>
</dependencies>
请求参数解密类
package luck.spring.boot.starter.encrypt.demo.advice;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import luck.spring.boot.starter.encrypt.demo.anno.Decrypt;
import luck.spring.boot.starter.encrypt.demo.config.LuckEncryptProperties;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonInputMessage;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.Type;
@ControllerAdvice
@RequiredArgsConstructor
public class LuckDecryptBodyAdvice implements RequestBodyAdvice {
private final LuckEncryptProperties luckEncryptProperties;
@Override
public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return methodParameter.hasMethodAnnotation(Decrypt.class) && luckEncryptProperties.isDecryptEnable() && methodParameter.hasParameterAnnotation(RequestBody.class);
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
byte[] bytes = IoUtil.readBytes(inputMessage.getBody());
byte[] decrypt = Base64Utils.decode(bytes);
return new MappingJacksonInputMessage(new ByteArrayInputStream(decrypt), inputMessage.getHeaders());
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return body;
}
@Override
public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
return StrUtil.EMPTY_JSON;
}
}
请求响应加密类
package luck.spring.boot.starter.encrypt.demo.advice;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import luck.spring.boot.starter.encrypt.demo.anno.Encrypt;
import luck.spring.boot.starter.encrypt.demo.config.LuckEncryptProperties;
import luck.spring.boot.starter.encrypt.demo.inter.LuckResultHandler;
import luck.spring.boot.starter.encrypt.demo.util.LuckSpringUtil;
import luck.spring.boot.starter.encrypt.demo.util.Result;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import java.nio.charset.StandardCharsets;
import java.util.List;
@ControllerAdvice
@RequiredArgsConstructor
public class LuckEncryptBodyAdvice implements ResponseBodyAdvice<Object> {
private final LuckEncryptProperties luckEncryptProperties;
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
Class<?> declaringClass = returnType.getDeclaringClass();
return declaringClass.isAnnotationPresent(RestController.class)
|| (declaringClass.isAnnotationPresent(Controller.class) && returnType.getMethod().isAnnotationPresent(ResponseBody.class));
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
Object result = body;
List<LuckResultHandler> beans = LuckSpringUtil.getBeans(LuckResultHandler.class);
if (CollUtil.isNotEmpty(beans)) {
for (LuckResultHandler handler : beans) {
if (!handler.support(body.getClass())) {
continue;
}
result = handler.handle(body);
}
}
if (luckEncryptProperties.isStandardResultEnable()) {
if (!(result instanceof Result)) {
result = Result.OK(result);
}
if (returnType.hasMethodAnnotation(Encrypt.class) && luckEncryptProperties.isEncryptEnable()) {
Result<Object> res = (Result<Object>) result;
Object data = res.getData();
if (ObjectUtil.isNotEmpty(data)) {
if (!(data instanceof String) || !JSONUtil.isTypeJSON(data.toString())) {
data = JSONUtil.toJsonStr(data);
}
String encrypt = Base64Utils.encodeToString(data.toString().getBytes(StandardCharsets.UTF_8));
res.setData(encrypt);
}
}
}
return result;
}
}
加密解密注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Decrypt {
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Encrypt {
}
自动配置属性类
@ConfigurationProperties(prefix = "luck.encrypt")
@Data
public class LuckEncryptProperties {
private boolean encryptEnable;
private boolean decryptEnable;
private boolean standardResultEnable;
}
处理响应结果使用的消息转换器
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(0, new MappingJackson2HttpMessageConverter());
}
}
starter提供给外部的响应结果处理类接口
package luck.spring.boot.starter.encrypt.demo.inter;
public interface LuckResultHandler<P, T, R> {
R handle(P p);
default boolean support(Class<?> clazz) {
if (clazz == null) {
return false;
}
Class<T> type = getType();
if (type == null) {
return false;
}
return clazz.equals(type);
}
Class<T> getType();
}
Spring容器操作的工具类
package luck.spring.boot.starter.encrypt.demo.util;
import cn.hutool.core.collection.CollUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.OrderComparator;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class LuckSpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
private static Environment environment;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
LuckSpringUtil.applicationContext = applicationContext;
LuckSpringUtil.environment = applicationContext.getEnvironment();
}
public static <T> T getBean(Class<T> tClass) {
return applicationContext.getBean(tClass);
}
public static <T> List<T> getBeans(Class<T> tClass) {
Collection<T> collection = Optional.ofNullable(getBeansMap(tClass))
.filter(CollUtil::isNotEmpty)
.map(Map::values)
.orElseGet(ArrayList::new);
return CollUtil.sort(collection, OrderComparator.INSTANCE);
}
public static <T> Map<String, T> getBeansMap(Class<T> tClass) {
return applicationContext.getBeansOfType(tClass);
}
public static String getProperty(String key) {
return environment.getProperty(key);
}
public static <T> T getProperty(String key, Class<T> tClass) {
return environment.getProperty(key, tClass);
}
}
统一响应结果类
package luck.spring.boot.starter.encrypt.demo.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @author anti
*/
@NoArgsConstructor
@Data
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Result<T> {
@JsonProperty(index = 0)
private int code;
@JsonProperty(index = 1)
private String message;
@JsonProperty(index = 2)
private T data;
public Result(int code, String message) {
this.code = code;
this.message = message;
}
public Result(int code, String message, T data) {
this(code, message);
this.data = data;
}
public static <T> Result<T> OK() {
return new Result<>(200, "success");
}
public static <T> Result<T> OK(String message) {
return new Result<>(200, message);
}
public static <T> Result<T> OK(String message, T data) {
return new Result<>(200, message, data);
}
public static <T> Result<T> OK(T data) {
return OK("请求成功", data);
}
public static <T> Result<T> FAIL() {
return FAIL(500, "fail");
}
public static <T> Result<T> FAIL(String message) {
return FAIL(500, message);
}
public static <T> Result<T> FAIL(int code, String message) {
return FAIL(code, message, null);
}
public static <T> Result<T> FAIL(int code, String message, T data) {
return new Result<>(code, String.format("请求失败,原因为:%s", message), data);
}
}
对外暴露的,写在spring.factories文件的配置类
@ComponentScan("luck.spring.boot.starter.encrypt.demo")
@EnableConfigurationProperties(LuckEncryptProperties.class)
public class LuckEncryptConfig {
}
resources文件下,META-INF目录下的spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
luck.spring.boot.starter.encrypt.demo.expose.LuckEncryptConfig
到此,starter已经完成了,需要使用maven:install安装到仓库,开始使用starter
maven依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>luck.spring.boot.starter.encrypt.demo</groupId>
<artifactId>luck-spring-boot-starter-encrypt-demo</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
接口
@RestController
public class LuckController {
@PostMapping("/test")
@Encrypt
@Decrypt
public String test(@RequestBody Map<String, Object> map) {
return JSONUtil.toJsonStr(map);
}
}
自定义starter提供的扩展接口,可以处理统一结果集
这就是简单的案例,告知怎么使用,下面做的其实没啥意义,真实根据业务来处理
package luck.spring.boot.handler;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import luck.spring.boot.starter.encrypt.demo.inter.LuckResultHandler;
import luck.spring.boot.starter.encrypt.demo.util.Result;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class ResultHandler implements LuckResultHandler<Object, String, Result> {
@Override
public Result handle(Object result) {
if ((result instanceof Result)) {
return (Result) result;
}
if (ObjectUtil.isEmpty(result)) {
return Result.OK(result);
}
if (result instanceof String && JSONUtil.isTypeJSON(result.toString())) {
result = JSONUtil.toBean(result.toString(), Map.class);
}
return Result.OK(result);
}
@Override
public Class<String> getType() {
return String.class;
}
}
启动类
@SpringBootApplication
public class App {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(App.class, args);
}
}