AVt天堂网 手机版,亚洲va久久久噜噜噜久久4399,天天综合亚洲色在线精品,亚洲一级Av无码毛片久久精品

當(dāng)前位置:首頁(yè) > 科技  > 軟件

SpringBoot 加密解密新招

來(lái)源: 責(zé)編: 時(shí)間:2024-07-09 18:18:24 123觀看
導(dǎo)讀1. 介紹在我們?nèi)粘5腏ava開發(fā)中,免不了和其他系統(tǒng)的業(yè)務(wù)交互,或者微服務(wù)之間的接口調(diào)用如果我們想保證數(shù)據(jù)傳輸?shù)陌踩?,?duì)接口出參加密,入?yún)⒔饷?。但是不想寫重?fù)代碼,我們可以提供一個(gè)通用starter,提供通用加密解密功能2.

1. 介紹

在我們?nèi)粘5腏ava開發(fā)中,免不了和其他系統(tǒng)的業(yè)務(wù)交互,或者微服務(wù)之間的接口調(diào)用0gx28資訊網(wǎng)——每日最新資訊28at.com

如果我們想保證數(shù)據(jù)傳輸?shù)陌踩瑢?duì)接口出參加密,入?yún)⒔饷堋?span style="display:none">0gx28資訊網(wǎng)——每日最新資訊28at.com

但是不想寫重復(fù)代碼,我們可以提供一個(gè)通用starter,提供通用加密解密功能0gx28資訊網(wǎng)——每日最新資訊28at.com

2. 前置知識(shí)

2.1 hutool-crypto加密解密工具

hutool-crypto提供了很多加密解密工具,包括對(duì)稱加密,非對(duì)稱加密,摘要加密等等,這不做詳細(xì)介紹。0gx28資訊網(wǎng)——每日最新資訊28at.com

2.2 request流只能讀取一次的問題

2.2.1 問題:

在接口調(diào)用鏈中,request的請(qǐng)求流只能調(diào)用一次,處理之后,如果之后還需要用到請(qǐng)求流獲取數(shù)據(jù),就會(huì)發(fā)現(xiàn)數(shù)據(jù)為空。0gx28資訊網(wǎng)——每日最新資訊28at.com

比如使用了filter或者aop在接口處理之前,獲取了request中的數(shù)據(jù),對(duì)參數(shù)進(jìn)行了校驗(yàn),那么之后就不能在獲取request請(qǐng)求流了0gx28資訊網(wǎng)——每日最新資訊28at.com

2.2.2 解決辦法

繼承HttpServletRequestWrapper,將請(qǐng)求中的流copy一份,復(fù)寫getInputStream和getReader方法供外部使用。每次調(diào)用后的getInputStream方法都是從復(fù)制出來(lái)的二進(jìn)制數(shù)組中進(jìn)行獲取,這個(gè)二進(jìn)制數(shù)組在對(duì)象存在期間一致存在。0gx28資訊網(wǎng)——每日最新資訊28at.com

使用Filter過濾器,在一開始,替換request為自己定義的可以多次讀取流的request。0gx28資訊網(wǎng)——每日最新資訊28at.com

這樣就實(shí)現(xiàn)了流的重復(fù)獲取InputStreamHttpServletRequestWrapper。0gx28資訊網(wǎng)——每日最新資訊28at.com

import org.apache.commons.io.IOUtils;import javax.servlet.ReadListener;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.IOException;import java.io.InputStreamReader;/** * 請(qǐng)求流支持多次獲取 */public class InputStreamHttpServletRequestWrapper extends HttpServletRequestWrapper {    /**     * 用于緩存輸入流     */    private ByteArrayOutputStream cachedBytes;    public InputStreamHttpServletRequestWrapper(HttpServletRequest request) {        super(request);    }    @Override    public ServletInputStream getInputStream() throws IOException {        if (cachedBytes == null) {            // 首次獲取流時(shí),將流放入 緩存輸入流 中            cacheInputStream();        }        // 從 緩存輸入流 中獲取流并返回        return new CachedServletInputStream(cachedBytes.toByteArray());    }    @Override    public BufferedReader getReader() throws IOException {        return new BufferedReader(new InputStreamReader(getInputStream()));    }    /**     * 首次獲取流時(shí),將流放入 緩存輸入流 中     */    private void cacheInputStream() throws IOException {        // 緩存輸入流以便多次讀取。為了方便, 我使用 org.apache.commons IOUtils        cachedBytes = new ByteArrayOutputStream();        IOUtils.copy(super.getInputStream(), cachedBytes);    }    /**     * 讀取緩存的請(qǐng)求正文的輸入流     * <p>     * 用于根據(jù) 緩存輸入流 創(chuàng)建一個(gè)可返回的     */    public static class CachedServletInputStream extends ServletInputStream {        private final ByteArrayInputStream input;        public CachedServletInputStream(byte[] buf) {            // 從緩存的請(qǐng)求正文創(chuàng)建一個(gè)新的輸入流            input = new ByteArrayInputStream(buf);        }        @Override        public boolean isFinished() {            return false;        }        @Override        public boolean isReady() {            return false;        }        @Override        public void setReadListener(ReadListener listener) {        }        @Override        public int read() throws IOException {            return input.read();        }    }}

HttpServletRequestInputStreamFilter 0gx28資訊網(wǎng)——每日最新資訊28at.com

import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import java.io.IOException;import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;/** * @description: *      請(qǐng)求流轉(zhuǎn)換為多次讀取的請(qǐng)求流 過濾器 */@Component@Order(HIGHEST_PRECEDENCE + 1)  // 優(yōu)先級(jí)最高public class HttpServletRequestInputStreamFilter implements Filter {    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        // 轉(zhuǎn)換為可以多次獲取流的request        HttpServletRequest httpServletRequest = (HttpServletRequest) request;        InputStreamHttpServletRequestWrapper inputStreamHttpServletRequestWrapper = new InputStreamHttpServletRequestWrapper(httpServletRequest);        // 放行        chain.doFilter(inputStreamHttpServletRequestWrapper, response);    }}

2.3 SpringBoot的參數(shù)校驗(yàn)validation

為了減少接口中,業(yè)務(wù)代碼之前的大量冗余的參數(shù)校驗(yàn)代碼0gx28資訊網(wǎng)——每日最新資訊28at.com

SpringBoot-validation提供了優(yōu)雅的參數(shù)校驗(yàn),入?yún)⒍际菍?shí)體類,在實(shí)體類字段上加上對(duì)應(yīng)注解,就可以在進(jìn)入方法之前,進(jìn)行參數(shù)校驗(yàn),如果參數(shù)錯(cuò)誤,會(huì)拋出錯(cuò)誤BindException,是不會(huì)進(jìn)入方法的。0gx28資訊網(wǎng)——每日最新資訊28at.com

這種方法,必須要求在接口參數(shù)上加注解@Validated或者是@Valid,但是很多情況下,我們希望在代碼中調(diào)用某個(gè)實(shí)體類的校驗(yàn)功能,所以需要如下工具類:0gx28資訊網(wǎng)——每日最新資訊28at.com

ParamException

import lombok.Getter;import java.util.List;/** * @description 自定義參數(shù)異常 */@Getterpublic class ParamException extends Exception {    private final List<String> fieldList;    private final List<String> msgList;    public ParamException(List<String> fieldList, List<String> msgList) {        this.fieldList = fieldList;        this.msgList = msgList;    }}

ValidationUtils

import javax.validation.ConstraintViolation;import javax.validation.Validation;import javax.validation.Validator;import java.util.LinkedList;import java.util.List;import java.util.Set;/** * @description 驗(yàn)證工具類 */public class ValidationUtils {    private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();    /**     * 驗(yàn)證數(shù)據(jù)     * @param object 數(shù)據(jù)     */    public static void validate(Object object) throws CustomizeException {        Set<ConstraintViolation<Object>> validate = VALIDATOR.validate(object);        // 驗(yàn)證結(jié)果異常        throwParamException(validate);    }    /**     * 驗(yàn)證數(shù)據(jù)(分組)     * @param object 數(shù)據(jù)     * @param groups 所在組     */    public static void validate(Object object, Class<?> ... groups) throws CustomizeException {        Set<ConstraintViolation<Object>> validate = VALIDATOR.validate(object, groups);        // 驗(yàn)證結(jié)果異常        throwParamException(validate);    }    /**     * 驗(yàn)證數(shù)據(jù)中的某個(gè)字段(分組)     * @param object 數(shù)據(jù)     * @param propertyName 字段名稱     */    public static void validate(Object object, String propertyName) throws CustomizeException {        Set<ConstraintViolation<Object>> validate = VALIDATOR.validateProperty(object, propertyName);        // 驗(yàn)證結(jié)果異常        throwParamException(validate);    }    /**     * 驗(yàn)證數(shù)據(jù)中的某個(gè)字段(分組)     * @param object 數(shù)據(jù)     * @param propertyName 字段名稱     * @param groups 所在組     */    public static void validate(Object object, String propertyName, Class<?> ... groups) throws CustomizeException {        Set<ConstraintViolation<Object>> validate = VALIDATOR.validateProperty(object, propertyName, groups);        // 驗(yàn)證結(jié)果異常        throwParamException(validate);    }    /**     * 驗(yàn)證結(jié)果異常     * @param validate 驗(yàn)證結(jié)果     */    private static void throwParamException(Set<ConstraintViolation<Object>> validate) throws CustomizeException {        if (validate.size() > 0) {            List<String> fieldList = new LinkedList<>();            List<String> msgList = new LinkedList<>();            for (ConstraintViolation<Object> next : validate) {                fieldList.add(next.getPropertyPath().toString());                msgList.add(next.getMessage());            }            throw new ParamException(fieldList, msgList);        }    }}

2.4 自定義starter

自定義starter步驟:0gx28資訊網(wǎng)——每日最新資訊28at.com

  • 創(chuàng)建工廠,編寫功能代碼。
  • 聲明自動(dòng)配置類,把需要對(duì)外提供的對(duì)象創(chuàng)建好,通過配置類統(tǒng)一向外暴露。
  • 在resource目錄下準(zhǔn)備一個(gè)名為spring/spring.factories的文件,以org.springframework.boot.autoconfigure.EnableAutoConfiguration為key,自動(dòng)配置類為value列表,進(jìn)行注冊(cè)。

2.5 RequestBodyAdvice和ResponseBodyAdvice

  • RequestBodyAdvice是對(duì)請(qǐng)求的json串進(jìn)行處理, 一般使用環(huán)境是處理接口參數(shù)的自動(dòng)解密。
  • ResponseBodyAdvice是對(duì)請(qǐng)求相應(yīng)的json傳進(jìn)行處理,一般用于相應(yīng)結(jié)果的加密。

3. 功能介紹

接口相應(yīng)數(shù)據(jù)的時(shí)候,返回的是加密之后的數(shù)據(jù)接口入?yún)⒌臅r(shí)候,接收的是解密之后的數(shù)據(jù),但是在進(jìn)入接口之前,會(huì)自動(dòng)解密,取得對(duì)應(yīng)的數(shù)據(jù)0gx28資訊網(wǎng)——每日最新資訊28at.com

4. 功能細(xì)節(jié)

加密解密使用對(duì)稱加密的AES算法,使用hutool-crypto模塊進(jìn)行實(shí)現(xiàn)0gx28資訊網(wǎng)——每日最新資訊28at.com

所有的實(shí)體類提取一個(gè)公共父類,包含屬性時(shí)間戳,用于加密數(shù)據(jù)返回之后的實(shí)效性,如果超過60分鐘,那么其他接口將不進(jìn)行處理。0gx28資訊網(wǎng)——每日最新資訊28at.com

如果接口加了加密注解EncryptionAnnotation,并且返回統(tǒng)一的json數(shù)據(jù)Result類,則自動(dòng)對(duì)數(shù)據(jù)進(jìn)行加密。如果是繼承了統(tǒng)一父類RequestBase的數(shù)據(jù),自動(dòng)注入時(shí)間戳,確保數(shù)據(jù)的時(shí)效性0gx28資訊網(wǎng)——每日最新資訊28at.com

如果接口加了解密注解DecryptionAnnotation,并且參數(shù)使用RequestBody注解標(biāo)注,傳入json使用統(tǒng)一格式RequestData類,并且內(nèi)容是繼承了包含時(shí)間長(zhǎng)的父類RequestBase,則自動(dòng)解密,并且轉(zhuǎn)為對(duì)應(yīng)的數(shù)據(jù)類型0gx28資訊網(wǎng)——每日最新資訊28at.com

功能提供Springboot的starter,實(shí)現(xiàn)開箱即用0gx28資訊網(wǎng)——每日最新資訊28at.com

5. 代碼實(shí)現(xiàn)

https://gitee.com/springboot-hlh/spring-boot-csdn/tree/master/09-spring-boot-interface-crypto0gx28資訊網(wǎng)——每日最新資訊28at.com

5.1 項(xiàng)目結(jié)構(gòu)

圖片圖片0gx28資訊網(wǎng)——每日最新資訊28at.com

5.2 crypto-common

5.2.1 結(jié)構(gòu)

圖片圖片0gx28資訊網(wǎng)——每日最新資訊28at.com

5.3 crypto-spring-boot-starter

5.3.1 接口

圖片圖片0gx28資訊網(wǎng)——每日最新資訊28at.com

5.3.2 重要代碼

crypto.properties AES需要的參數(shù)配置;0gx28資訊網(wǎng)——每日最新資訊28at.com

# 模式    crypto.mode=CTS# 補(bǔ)碼方式 crypto.padding=PKCS5Padding# 秘鑰crypto.key=testkey123456789# 鹽crypto.iv=testiv1234567890

spring.factories 自動(dòng)配置文件;0gx28資訊網(wǎng)——每日最新資訊28at.com

org.springframework.boot.autoconfigure.EnableAutoCnotallow=/        xyz.hlh.crypto.config.AppConfig

CryptConfig AES需要的配置參數(shù);0gx28資訊網(wǎng)——每日最新資訊28at.com

import cn.hutool.crypto.Mode;import cn.hutool.crypto.Padding;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.Getter;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.PropertySource;import java.io.Serializable;/** * @description: AES需要的配置參數(shù) */@Configuration@ConfigurationProperties(prefix = "crypto")@PropertySource("classpath:crypto.properties")@Data@EqualsAndHashCode@Getterpublic class CryptConfig implements Serializable {    private Mode mode;    private Padding padding;    private String key;    private String iv;}

AppConfig 自動(dòng)配置類;0gx28資訊網(wǎng)——每日最新資訊28at.com

import cn.hutool.crypto.symmetric.AES;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.annotation.Resource;import java.nio.charset.StandardCharsets;/** * @description: 自動(dòng)配置類 */@Configurationpublic class AppConfig {    @Resource    private CryptConfig cryptConfig;    @Bean    public AES aes() {        return new AES(cryptConfig.getMode(), cryptConfig.getPadding(), cryptConfig.getKey().getBytes(StandardCharsets.UTF_8), cryptConfig.getIv().getBytes(StandardCharsets.UTF_8));    }}

DecryptRequestBodyAdvice 請(qǐng)求自動(dòng)解密;0gx28資訊網(wǎng)——每日最新資訊28at.com

import com.fasterxml.jackson.databind.ObjectMapper;import lombok.SneakyThrows;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.MethodParameter;import org.springframework.http.HttpInputMessage;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.context.request.RequestAttributes;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;import xyz.hlh.crypto.annotation.DecryptionAnnotation;import xyz.hlh.crypto.common.exception.ParamException;import xyz.hlh.crypto.constant.CryptoConstant;import xyz.hlh.crypto.entity.RequestBase;import xyz.hlh.crypto.entity.RequestData;import xyz.hlh.crypto.util.AESUtil;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import java.io.IOException;import java.lang.reflect.Type;/** * @description: requestBody 自動(dòng)解密 */@ControllerAdvicepublic class DecryptRequestBodyAdvice implements RequestBodyAdvice {    @Autowired    private ObjectMapper objectMapper;    /**     * 方法上有DecryptionAnnotation注解的,進(jìn)入此攔截器     * @param methodParameter 方法參數(shù)對(duì)象     * @param targetType 參數(shù)的類型     * @param converterType 消息轉(zhuǎn)換器     * @return true,進(jìn)入,false,跳過     */    @Override    public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {        return methodParameter.hasMethodAnnotation(DecryptionAnnotation.class);    }    @Override    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {        return inputMessage;    }    /**     * 轉(zhuǎn)換之后,執(zhí)行此方法,解密,賦值     * @param body spring解析完的參數(shù)     * @param inputMessage 輸入?yún)?shù)     * @param parameter 參數(shù)對(duì)象     * @param targetType 參數(shù)類型     * @param converterType 消息轉(zhuǎn)換類型     * @return 真實(shí)的參數(shù)     */    @SneakyThrows    @Override    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {        // 獲取request        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;        if (servletRequestAttributes == null) {            throw new ParamException("request錯(cuò)誤");        }        HttpServletRequest request = servletRequestAttributes.getRequest();        // 獲取數(shù)據(jù)        ServletInputStream inputStream = request.getInputStream();        RequestData requestData = objectMapper.readValue(inputStream, RequestData.class);        if (requestData == null || StringUtils.isBlank(requestData.getText())) {            throw new ParamException("參數(shù)錯(cuò)誤");        }        // 獲取加密的數(shù)據(jù)        String text = requestData.getText();        // 放入解密之前的數(shù)據(jù)        request.setAttribute(CryptoConstant.INPUT_ORIGINAL_DATA, text);        // 解密        String decryptText = null;        try {            decryptText = AESUtil.decrypt(text);        } catch (Exception e) {            throw new ParamException("解密失敗");        }        if (StringUtils.isBlank(decryptText)) {            throw new ParamException("解密失敗");        }        // 放入解密之后的數(shù)據(jù)        request.setAttribute(CryptoConstant.INPUT_DECRYPT_DATA, decryptText);        // 獲取結(jié)果        Object result = objectMapper.readValue(decryptText, body.getClass());        // 強(qiáng)制所有實(shí)體類必須繼承RequestBase類,設(shè)置時(shí)間戳        if (result instanceof RequestBase) {            // 獲取時(shí)間戳            Long currentTimeMillis = ((RequestBase) result).getCurrentTimeMillis();            // 有效期 60秒            long effective = 60*1000;            // 時(shí)間差            long expire = System.currentTimeMillis() - currentTimeMillis;            // 是否在有效期內(nèi)            if (Math.abs(expire) > effective) {                throw new ParamException("時(shí)間戳不合法");            }            // 返回解密之后的數(shù)據(jù)            return result;        } else {            throw new ParamException(String.format("請(qǐng)求參數(shù)類型:%s 未繼承:%s", result.getClass().getName(), RequestBase.class.getName()));        }    }    /**     * 如果body為空,轉(zhuǎn)為空對(duì)象     * @param body spring解析完的參數(shù)     * @param inputMessage 輸入?yún)?shù)     * @param parameter 參數(shù)對(duì)象     * @param targetType 參數(shù)類型     * @param converterType 消息轉(zhuǎn)換類型     * @return 真實(shí)的參數(shù)     */    @SneakyThrows    @Override    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {        String typeName = targetType.getTypeName();        Class<?> bodyClass = Class.forName(typeName);        return bodyClass.newInstance();    }}

EncryptResponseBodyAdvice 相應(yīng)自動(dòng)加密;0gx28資訊網(wǎng)——每日最新資訊28at.com

import cn.hutool.json.JSONUtil;import com.fasterxml.jackson.databind.ObjectMapper;import lombok.SneakyThrows;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.MethodParameter;import org.springframework.http.MediaType;import org.springframework.http.ResponseEntity;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.server.ServerHttpRequest;import org.springframework.http.server.ServerHttpResponse;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;import xyz.hlh.crypto.annotation.EncryptionAnnotation;import xyz.hlh.crypto.common.entity.Result;import xyz.hlh.crypto.common.exception.CryptoException;import xyz.hlh.crypto.entity.RequestBase;import xyz.hlh.crypto.util.AESUtil;import java.lang.reflect.Type;@ControllerAdvicepublic class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Result<?>> {    @Autowired    private ObjectMapper objectMapper;    @Override    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {        ParameterizedTypeImpl genericParameterType = (ParameterizedTypeImpl)returnType.getGenericParameterType();        // 如果直接是Result,則返回        if (genericParameterType.getRawType() == Result.class && returnType.hasMethodAnnotation(EncryptionAnnotation.class)) {            return true;        }        if (genericParameterType.getRawType() != ResponseEntity.class) {            return false;        }        // 如果是ResponseEntity<Result>        for (Type type : genericParameterType.getActualTypeArguments()) {            if (((ParameterizedTypeImpl) type).getRawType() == Result.class && returnType.hasMethodAnnotation(EncryptionAnnotation.class)) {                return true;            }        }        return false;    }    @SneakyThrows    @Override    public Result<?> beforeBodyWrite(Result<?> body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {        // 加密        Object data = body.getData();        // 如果data為空,直接返回        if (data == null) {            return body;        }        // 如果是實(shí)體,并且繼承了Request,則放入時(shí)間戳        if (data instanceof RequestBase) {            ((RequestBase)data).setCurrentTimeMillis(System.currentTimeMillis());        }        String dataText = JSONUtil.toJsonStr(data);        // 如果data為空,直接返回        if (StringUtils.isBlank(dataText)) {            return body;        }        // 如果位數(shù)小于16,報(bào)錯(cuò)        if (dataText.length() < 16) {            throw new CryptoException("加密失敗,數(shù)據(jù)小于16位");        }        String encryptText = AESUtil.encryptHex(dataText);        return Result.builder()                .status(body.getStatus())                .data(encryptText)                .message(body.getMessage())                .build();    }}

5.4 crypto-test

5.4.1 結(jié)構(gòu)

圖片圖片0gx28資訊網(wǎng)——每日最新資訊28at.com

5.4.2 重要代碼

application.yml 配置文件;0gx28資訊網(wǎng)——每日最新資訊28at.com

spring:  mvc:    format:      date-time: yyyy-MM-dd HH:mm:ss      date: yyyy-MM-dd  # 日期格式化  jackson:    date-format: yyyy-MM-dd HH:mm:ss    time-zone: GMT+8

Teacher 實(shí)體類;0gx28資訊網(wǎng)——每日最新資訊28at.com

import lombok.AllArgsConstructor;import lombok.Data;import lombok.EqualsAndHashCode;import lombok.NoArgsConstructor;import org.hibernate.validator.constraints.Range;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;import java.io.Serializable;import java.util.Date;/** * @description: Teacher實(shí)體類,使用SpringBoot的validation校驗(yàn) */@Data@NoArgsConstructor@AllArgsConstructor@EqualsAndHashCode(callSuper = true)public class Teacher extends RequestBase implements Serializable {    @NotBlank(message = "姓名不能為空")    private String name;    @NotNull(message = "年齡不能為空")    @Range(min = 0, max = 150, message = "年齡不合法")    private Integer age;    @NotNull(message = "生日不能為空")    private Date birthday;}

TestController 測(cè)試Controller;0gx28資訊網(wǎng)——每日最新資訊28at.com

import org.springframework.http.ResponseEntity;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RestController;import xyz.hlh.crypto.annotation.DecryptionAnnotation;import xyz.hlh.crypto.annotation.EncryptionAnnotation;import xyz.hlh.crypto.common.entity.Result;import xyz.hlh.crypto.common.entity.ResultBuilder;import xyz.hlh.crypto.entity.Teacher;/** * @description: 測(cè)試Controller */@RestControllerpublic class TestController implements ResultBuilder {    /**     * 直接返回對(duì)象,不加密     * @param teacher Teacher對(duì)象     * @return 不加密的對(duì)象     */    @PostMapping("/get")    public ResponseEntity<Result<?>> get(@Validated @RequestBody Teacher teacher) {        return success(teacher);    }    /**     * 返回加密后的數(shù)據(jù)     * @param teacher Teacher對(duì)象     * @return 返回加密后的數(shù)據(jù) ResponseBody<Result>格式     */    @PostMapping("/encrypt")    @EncryptionAnnotation    public ResponseEntity<Result<?>> encrypt(@Validated @RequestBody Teacher teacher) {        return success(teacher);    }    /**     * 返回加密后的數(shù)據(jù)     * @param teacher Teacher對(duì)象     * @return 返回加密后的數(shù)據(jù) Result格式     */    @PostMapping("/encrypt1")    @EncryptionAnnotation    public Result<?> encrypt1(@Validated @RequestBody Teacher teacher) {        return success(teacher).getBody();    }    /**     * 返回解密后的數(shù)據(jù)     * @param teacher Teacher對(duì)象     * @return 返回解密后的數(shù)據(jù)     */    @PostMapping("/decrypt")    @DecryptionAnnotation    public ResponseEntity<Result<?>> decrypt(@Validated @RequestBody Teacher teacher) {        return success(teacher);    }}

0gx28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.tebozhan.com/showinfo-26-99891-0.htmlSpringBoot 加密解密新招

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 十個(gè)罕見的 HTML 標(biāo)簽,幾乎無(wú)人使用 - &lt;dialog&gt;、&lt;bdo&gt;等等

下一篇: 掌握Promise:從基礎(chǔ)到高級(jí)應(yīng)用的全面指

標(biāo)簽:
  • 熱門焦點(diǎn)
  • 掘力計(jì)劃第 20 期:Flutter 混合開發(fā)的混亂之治

    在掘力計(jì)劃系列活動(dòng)第20場(chǎng),《Flutter 開發(fā)實(shí)戰(zhàn)詳解》作者,掘金優(yōu)秀作者,Github GSY 系列目負(fù)責(zé)人戀貓的小郭分享了Flutter 混合開發(fā)的混亂之治。Flutter 基于自研的 Skia 引擎
  • 學(xué)習(xí)JavaScript的10個(gè)理由...

    作者 | Simplilearn編譯 | 王瑞平當(dāng)你決心學(xué)習(xí)一門語(yǔ)言的時(shí)候,很難選擇到底應(yīng)該學(xué)習(xí)哪一門,常用的語(yǔ)言有Python、Java、JavaScript、C/CPP、PHP、Swift、C#、Ruby、Objective-
  • 如何使用JavaScript創(chuàng)建一只圖像放大鏡?

    譯者 | 布加迪審校 | 重樓如果您曾經(jīng)瀏覽過購(gòu)物網(wǎng)站,可能遇到過圖像放大功能。它可以讓您放大圖像的特定區(qū)域,以便瀏覽。結(jié)合這個(gè)小小的重要功能可以大大改善您網(wǎng)站的用戶體驗(yàn)
  • 每天一道面試題-CPU偽共享

    前言:了不起:又到了每天一到面試題的時(shí)候了!學(xué)弟,最近學(xué)習(xí)的怎么樣啊 了不起學(xué)弟:最近學(xué)習(xí)的還不錯(cuò),每天都在學(xué)習(xí),每天都在進(jìn)步! 了不起:那你最近學(xué)習(xí)的什么呢? 了不起學(xué)弟:最近在學(xué)習(xí)C
  • 騰訊蓋樓,字節(jié)拆墻

    來(lái)源 | 光子星球撰文 | 吳坤諺編輯 | 吳先之&ldquo;想重溫暴刷深淵、30+技能搭配暴搓到爽的游戲體驗(yàn)嗎?一起上晶核,即刻暴打!&rdquo;曾憑借直播騰訊旗下代理格斗游戲《DNF》一
  • 華為發(fā)布HarmonyOS 4:更好玩、更流暢、更安全

    在8月4日的華為開發(fā)者大會(huì)2023(HDC.Together)大會(huì)上,HarmonyOS 4正式發(fā)布。自2019年發(fā)布以來(lái),HarmonyOS一直以用戶為中心,經(jīng)歷四年多的發(fā)展HarmonyOS已
  • 支持aptX Lossless無(wú)損傳輸 iQOO TWS 1賽道版發(fā)布限時(shí)優(yōu)惠價(jià)369元

    2023年7月4日,“無(wú)損音質(zhì),聲動(dòng)人心”iQOO TWS 1正式發(fā)布,支持aptX Lossless無(wú)損傳輸,限時(shí)優(yōu)惠價(jià)369元。iQOO TWS 1耳機(jī)率先支持端到端aptX Lossless無(wú)
  • iQOO Neo8系列今日官宣:首發(fā)天璣9200+ 全球安卓最強(qiáng)芯!

    在昨日舉行的的聯(lián)發(fā)科新一代旗艦芯片天璣9200+的發(fā)布會(huì)上,iQOO官方也正式宣布,全新的iQOO Neo8系列新品將全球首發(fā)搭載這款當(dāng)前性能最強(qiáng)大的移動(dòng)平臺(tái)
  • iQOO Neo8系列或定檔5月23日:首發(fā)天璣9200+ 安卓跑分王者

    去年10月,iQOO推出了iQOO Neo7系列機(jī)型,不僅搭載了天璣9000+,而且是同價(jià)位唯一一款天璣9000+直屏旗艦,一經(jīng)上市便受到了用戶的廣泛關(guān)注。在時(shí)隔半年后,
Top