记一次实战项目所学(通用接口篇)
1.加解密工具(AES,RSA,MD5) 账号登录时可用
a.引依赖
<dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.14</version></dependency>
b. AES加密
import org.apache.tomcat.util.codec.binary.Base64;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;/*** AES: Advanced Encryption Standard 高级加密标准* 最常见的对称加密算法,即加密和解密使用同样的密钥,加密结果可逆* 特点:加密速度非常快,适合经常发送数据的场合**/
public class AESUtil {private static final String KEY_ALGORITHM = "AES";private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };private final Cipher decryptCipher;private final Cipher encryptCipher;private final String seed;public AESUtil(String seed) throws Exception {this.seed = seed;decryptCipher = Cipher.getInstance(KEY_ALGORITHM);encryptCipher = Cipher.getInstance(KEY_ALGORITHM);decryptCipher.init(Cipher.DECRYPT_MODE, this.getSecretKey());encryptCipher.init(Cipher.ENCRYPT_MODE, this.getSecretKey());}public String decrypt(String content) throws Exception {byte[] bytes = Base64.decodeBase64(content);byte[] result = decryptCipher.doFinal(bytes);return new String(result, StandardCharsets.UTF_8);}public String encrypt(String content) throws Exception {byte[] result = encryptCipher.doFinal(content.getBytes(StandardCharsets.UTF_8));return Base64.encodeBase64String(result);}public SecretKey getSecretKey() throws Exception {SecureRandom random = SecureRandom.getInstance("SHA1PRNG");random.setSeed(seed.getBytes());KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);kg.init(128, random);return kg.generateKey();}}
encrypt 方法用于加密
decrypt 方法用于解密
c. RSA加密
import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;/*** RSA加密* 非对称加密,有公钥和私钥之分,公钥用于数据加密,私钥用于数据解密。加密结果可逆* 公钥一般提供给外部进行使用,私钥需要放置在服务器端保证安全性。* 特点:加密安全性很高,但是加密速度较慢* 用于用户登录场景*/
public class RSAUtil {private static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQk33iNdA8Iey7J6XrBsidqn6u8EDLWPHsfEUgLQ3qiTikhPKDTzZkpAfU/O0x6NvSKa7Dp0+uqWT3vnW1De0+3u8mCYdVfOdH94VG4xg5U5UrRJei8HhPiXuvKQ+6NBtebCCW5adZ4pBgOiU14cJLhVmm+dYiLo3IDD5LqrlomQIDAQAB";private static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJCTfeI10Dwh7LsnpesGyJ2qfq7wQMtY8ex8RSAtDeqJOKSE8oNPNmSkB9T87THo29IprsOnT66pZPe+dbUN7T7e7yYJh1V850f3hUbjGDlTlStEl6LweE+Je68pD7o0G15sIJblp1nikGA6JTXhwkuFWab51iIujcgMPkuquWiZAgMBAAECgYA1UT9mciQWWQh9yNRmhXzssFjB2TZ8B5RIe1fe0t7D9NEf0yvAgzDzEo8U3CX5dv/CVL7vxr8bEbt7phCwsa8hJiLEOr7hLZaJzXVTbvfqb91oCZGNkqDQ3NJfGBMVgUmltEYF2Bbk3U0NDyat+Gu54tRd2OH+adJYKsD0XYeDBQJBAN5FE8E04A4FA1q8mQbVTSVJDYIEJwOrdC0r3iZ7za5CyXGk+br8pFalRePFaksRGdN32+mYhDKVNrNHspAObVMCQQCmhBsD+xiWrmpnrzeIfCW1cX8qRC3/RMkq0ACw3l6YedNFdN2Tb5WsRHmcbCI9y8mfLHiG/X1R+zHZKG67EKjjAkAmvAkGSY2mQ89i160fWLq5/bIh71FRPWbgnF15fWfJr4/lgyeWI4MMKn80g2nTrSZACQpE+jRHkGNY+OywWCNLAkEAli5nvztkfeJpDYK2b16pE/B9ZL2BTs3XMcnQFbU5VAPsTKSOgz8MmwZXOIE+kMWP3wPY4McXlC0eVGFnHUh1SQJAeAl3RPk+XbZDMYfPkStRJwocG9Ap+88mwTgR1I7uPzZ1aM84/WsQskiVMXv2SZLmMWvYtnhIKosL6IACp2AcDA==";public static void main(String[] args) throws Exception{String str = RSAUtil.encrypt("123456");System.out.println(str);}public static String getPublicKeyStr(){return PUBLIC_KEY;}public static RSAPublicKey getPublicKey() throws Exception {byte[] decoded = Base64.decodeBase64(PUBLIC_KEY);return (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));}public static RSAPrivateKey getPrivateKey() throws Exception {byte[] decoded = Base64.decodeBase64(PRIVATE_KEY);return (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));}//获得公钥和私钥public static RSAKey generateKeyPair() throws NoSuchAlgorithmException {KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");keyPairGen.initialize(1024, new SecureRandom());KeyPair keyPair = keyPairGen.generateKeyPair();RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));String privateKeyString = new String(Base64.encodeBase64(privateKey.getEncoded()));return new RSAKey(privateKey, privateKeyString, publicKey, publicKeyString);}public static String encrypt(String source) throws Exception {byte[] decoded = Base64.decodeBase64(PUBLIC_KEY);RSAPublicKey rsaPublicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));Cipher cipher = Cipher.getInstance("RSA");cipher.init(1, rsaPublicKey);return Base64.encodeBase64String(cipher.doFinal(source.getBytes(StandardCharsets.UTF_8)));}public static Cipher getCipher() throws Exception {byte[] decoded = Base64.decodeBase64(PRIVATE_KEY);RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));Cipher cipher = Cipher.getInstance("RSA");cipher.init(2, rsaPrivateKey);return cipher;}public static String decrypt(String text) throws Exception {Cipher cipher = getCipher();byte[] inputByte = Base64.decodeBase64(text.getBytes(StandardCharsets.UTF_8));return new String(cipher.doFinal(inputByte));}public static class RSAKey {private RSAPrivateKey privateKey;private String privateKeyString;private RSAPublicKey publicKey;public String publicKeyString;public RSAKey(RSAPrivateKey privateKey, String privateKeyString, RSAPublicKey publicKey, String publicKeyString) {this.privateKey = privateKey;this.privateKeyString = privateKeyString;this.publicKey = publicKey;this.publicKeyString = publicKeyString;}public RSAPrivateKey getPrivateKey() {return this.privateKey;}public void setPrivateKey(RSAPrivateKey privateKey) {this.privateKey = privateKey;}public String getPrivateKeyString() {return this.privateKeyString;}public void setPrivateKeyString(String privateKeyString) {this.privateKeyString = privateKeyString;}public RSAPublicKey getPublicKey() {return this.publicKey;}public void setPublicKey(RSAPublicKey publicKey) {this.publicKey = publicKey;}public String getPublicKeyString() {return this.publicKeyString;}public void setPublicKeyString(String publicKeyString) {this.publicKeyString = publicKeyString;}}
}
把公钥返回前端,用公钥把前端输入密码进行加密,将暗文返回后端
generateKeyPair用于生成公钥和私钥
encrypt 方法用于加密 (根据公钥)
decrypt 方法用于解密
MD5加密
import org.apache.commons.codec.digest.DigestUtils;import java.io.UnsupportedEncodingException;/*** MD5加密* 单向加密算法* 特点:加密速度快,不需要秘钥,但是安全性不高,需要搭配随机盐值使用**/
public class MD5Util {public static String sign(String content, String salt, String charset) {content = content + salt;return DigestUtils.md5Hex(getContentBytes(content, charset));}public static boolean verify(String content, String sign, String salt, String charset) {content = content + salt;String mysign = DigestUtils.md5Hex(getContentBytes(content, charset));return mysign.equals(sign);}private static byte[] getContentBytes(String content, String charset) {if (!"".equals(charset)) {try {return content.getBytes(charset);} catch (UnsupportedEncodingException var3) {throw new RuntimeException("MD5签名过程中出现错误,指定的编码集错误");}} else {return content.getBytes();}}
}
sign用于加密 (内容,加密盐,编码)
verify用于解密
2. Json返回数据类
public class JsonResponse<T> {private String code;private String msg;private T data;public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public T getData() {return data;}public void setData(T data) {this.data = data;}public JsonResponse(String code, String msg) {this.code = code;this.msg = msg;}public JsonResponse(T data) {this.data = data;msg="成功";code="0";}//不需要返回前端但请求成功public static JsonResponse<String> success(){return new JsonResponse<>(null);}public static JsonResponse<String> success(String data){return new JsonResponse<>(data);}public static JsonResponse<String> fail(){return new JsonResponse<>("1","失败");}public static JsonResponse<String> fail(String code ,String msg){return new JsonResponse<>(code,msg);}
}
将 状态码和状态与数据封装
3.Json转化配置(将返回的json搞成看得懂的)
引入依赖
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.78</version></dependency>
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;import java.util.ArrayList;
import java.util.List;@Configuration
public class JsonHttpMsgConvertConfig {@Bean@Primarypublic HttpMessageConverters fastJsonHttpMessageConvertes(){//json转化FastJsonHttpMessageConverter fastConverter=new FastJsonHttpMessageConverter();FastJsonConfig fastJsonConfig=new FastJsonConfig();fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, //格式化输出SerializerFeature.WriteNullStringAsEmpty, //把null值的属性转化为空字符串SerializerFeature.WriteNullListAsEmpty, //同上SerializerFeature.WriteMapNullValue, //同上SerializerFeature.MapSortField,SerializerFeature.DisableCircularReferenceDetect); //禁用循环引用fastConverter.setFastJsonConfig(fastJsonConfig);return new HttpMessageConverters(fastConverter);}
}
4.全局异常处理
import com.imooc.bilibili.domain.JsonResponse;
import com.imooc.bilibili.domain.except.ConditionException;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest;@ControllerAdvice //@ControllerAdvice,是Spring3.2提供的新注解,它是一个Controller增强器,可对controller中被 @RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理@Order(Ordered.HIGHEST_PRECEDENCE)
public class CommonGlobalExceptionHandler {@ExceptionHandler(value = Exception.class)@ResponseBody //返回参数是responsebodypublic JsonResponse<String> commonExceptionHandler(HttpServletRequest httpServletRequest,Exception e){String errorMsg =e.getMessage();//如果e是condiException类型的话就会有个code状态码if(e instanceof ConditionException){String errorCode=((ConditionException)e).getCode();return new JsonResponse<>(errorCode,errorMsg);}else {return new JsonResponse<>("500",errorMsg);}}
}
如果exception是conditionException的话,可以获得一个状态码,再用Json返回数据类返回,用于主动抛出异常,如密码错误等
配置分情况处理异常(ConditionException)
补充runtimeException里没有的东西,多了一个code返回值表示状态码。
public class ConditionException extends RuntimeException {private static final long serialVersionUID =1L; //序列版本号private String code;public ConditionException(String code,String name){super(name);this.code=code;}public ConditionException(String name){super(name);code="500";}public String getCode() {return code;}public void setCode(String code) {this.code = code;}
}