Java开发中常用工具类 -ZHF

Java常用工具类

一. 序列化 / 反序列化

用于将 对象 转为 JsonJson对象

1. Json - jackson

Maven 包管理:

  • 依赖(.pom):

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-json</artifactId>
        <version>2.5.5</version>
    </dependency>
    

    在这里插入图片描述

  • 工具类(.java

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public class JsonUtil {
        // 创建ObjectMapper对象
        private static final ObjectMapper MAPPER = new ObjectMapper();
    
        // 对象转为Json
        public static String objToJson(Object obj){
            try {
               return MAPPER.writeValueAsString(obj);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        // Json转对象
        public static <T> T  jsonToBean(String json,Class<T> beanType){
            try {
               return MAPPER.readValue(json,beanType);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

解决了LinkedHashMap转换类型出错的问题(从Redis取出来的数据)

// 解决LinkedHashMap转换问题
String cartItemDtoStr = JsonUtil.objToJson(redisTemplate.opsForHash().get(RedisKeyConfig.CART_KEY_USER_ID + userId, key));
CartItemDto cartItemDto = JsonUtil.jsonToBean(cartItemDtoStr, CartItemDto.class);

二. 鉴权

1. Jwt生成token

Maven 包管理:

  • 依赖(.pom):

    <!-- JWT -->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.0</version>
    </dependency>
    <!-- 解决xml报错问题(jwt引起) -->
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-core</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
    
  • 工具类(.java

    import io.jsonwebtoken.Claims;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.SignatureAlgorithm;
    import project.pet.request.LoginUser;
    
    import java.util.Date;
    
    public class JwtUtil {
        /**
         * token 过期时间,一般是7天,可根据业务进行调整
         * 30 分钟过期
         */
        private static final long EXPIRE = 1000 * 60 * 30;
        /**
         * 加密的秘钥
         */
        private static final String SECRET = "xxit.comabc";
        /**
         * 令牌前缀
         */
        private static final String TOKEN_PREFIX = "xxitcrm";
        /**
         * subject
         */
        private static final String SUBJECT = "login";
    
        /**
         * 根据用户信息,生成token(令牌) *
         */
        public static String geneJsonWebToken(/* 添加内容的对象 */LoginUser loginUser) {
            if (loginUser == null) {
                throw new NullPointerException("loginUser对象为空");
            }
            // 过期时间
            Date expirationTime = new Date(System.currentTimeMillis() + EXPIRE);
            String token = Jwts.builder().setSubject(SUBJECT)
                    // 设置JWT的payload,包含用户ID、头像和姓名
                    .claim("id", loginUser.getId())
                    .claim("loginUser", loginUser)
                	// 过期时间(毫秒Long类型)
                    .claim("expirationTime", expirationTime)
                    // 设置JWT的签发时间
                    .setIssuedAt(new Date())
                    // 设置JWT的过期时间
                    .setExpiration(expirationTime)
                    // 使用HS256算法和密钥对JWT进行签名
                    .signWith(SignatureAlgorithm.HS256, SECRET)
                    // 生成JWT字符串
                    .compact();
            // 前缀加生成的token
            token = TOKEN_PREFIX + token;
            return token;
        }
    
        /**
         * 校验token的方法
         */
        public static Claims checkJWT(String token) {
            try {
                // 使用密钥解析token,获取Claims对象
                return Jwts.parser().setSigningKey(SECRET)
                        // 这一步是把前缀去了
                        .parseClaimsJws(token.replace(TOKEN_PREFIX, "")).getBody(); // 返回Claims对象
            } catch (Exception e) { // 解析失败
                System.out.println("jwt token解析失败"); // 输出错误信息
                return null; // 返回null
            }
        }
    
    }
    

解析token内容

  • 通过工具类里 checkJWT(String token) 来解析 token 里的用户信息(数据)
Claims claims = JwtUtil.checkJWT(token);

// 获取封装的内容(获取在工具类里设置的payload)
Integer id = (Integer) claims.get("id");
LoginUser loginuser = (LoginUser) claims.get("loginuser");
  • 获取当前Token的创建时间与过期时间
// 创建生成token的对象
LoginUser loginUser = new LoginUser();
loginUser.setId(1L);

// 生成token
String token = JwtUtil.geneJsonWebToken(loginUser);

// 解析token
Claims claims = JwtUtil.checkJWT(token);

// 获取token过期时间(毫秒,在payload里设置的expirationTime字段 - Long类型)
// Tips:以下获取的都是时间戳!!!!
Long expirationTime = (Long) claims.get("expirationTime");

// 获取自带的过期时间与生成时间(Integer类型 - 秒)
Integer createTime = (Integer) claims.get("iat");   // 创建时间
Integer destroyTime = (Integer) claims.get("exp");  // 销毁时间

System.out.println(expirationTime); // 1688992877754
System.out.println(createTime);     // 1688991077
System.out.println(destroyTime);    // 1688992877

时间戳转换网站:时间戳(Unix timestamp)-时间戳转换器

三. 统一返回数据格式

前后端数据交互,统一返回 Json 格式

1. JsonData

Maven 包管理:

  • 依赖(.pom

    <!-- Jackson -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-json</artifactId>
        <version>2.5.5</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
    </dependency>
    <!-- 上面的jackson也可以改为fastjson -->
    <!-- 改为fastjason时需要修改下面工具类的响应方法 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.79</version>
    </dependency>
    
  • 工具类(.java

    // jackson
    import com.fasterxml.jackson.databind.ObjectMapper;
    // fastjson
    import com.alibaba.fastjson.JSON;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    /**
     * 响应json 通用类
     */
    public class JsonData {
    
        /**
         * 状态码 0 表示成功,1表示处理中,-1表示失败
         */
        private Integer code;
        /**
         * 数据
         */
        private Object data;
        /**
         * 描述
         */
        private String msg;
    
        /**
         * 空构造
         */
        public JsonData() {
        }
    
        /**
         * 带参构造
         * @param code
         * @param data
         * @param msg
         */
        public JsonData(Integer code, Object data, String msg) {
            this.code = code;
            this.data = data;
            this.msg = msg;
        }
    
        /**
         * 成功,不需要传入数据
         * @return
         */
        public static JsonData buildSuccess() {
            return new JsonData(200, null, null);
        }
        /**
         *  成功,传入数据
         * @param data
         * @return
         */
        public static JsonData buildSuccess(Object data) {
            return new JsonData(200, data, null);
        }
    
        /**
         * 成功,传入数据和消息
         * @param data
         * @param msg
         * @return
         */
        public static JsonData buildSuccess(Object data,String msg){
            return new JsonData(200,data,msg);
        }
    
        /**
         * 失败,传入描述信息
         * @param msg
         * @return
         */
        public static JsonData buildError(String msg) {
            return new JsonData(-1, null, msg);
        }
        public static JsonData buildError(String msg,Object data) {
            return new JsonData(-1, data, msg);
        }
    
        /**
         * 自定义状态码和错误信息
         * @param code
         * @param msg
         * @return
         */
        public static JsonData buildCodeAndMsg(int code, String msg) {
            return new JsonData(code, null, msg);
        }
    
        /**
         * 自定义状态码、数据以及消息信息
         * @param code
         * @param msg
         * @param data
         * @return
         */
        public static JsonData buildCodeAndMsgAndData(int code, String msg,Object data) {
            return new JsonData(code, data, msg);
        }
    
        /**
         * 将 封装的JsonData 对象转成json后响应客户端
         * @param response
         * @param jsonData
         * @return
         */
        public static void returnJson(HttpServletResponse response,JsonData jsonData){
    
            try {
                response.setContentType("text/json;charset=utf-8");
                PrintWriter out = response.getWriter();
                // 使用jackson(两个只能选择一个啊)
                String result = new ObjectMapper().writeValueAsString(jsonData);
                // 使用fastjson
                // String result = JSON.toJSONString(jsonData);
                out.print(result);
                out.flush();
                out.close();
    
            } catch (IOException e) {
                System.err.println("响应json数据异常!!!");
                e.printStackTrace();
            }
        }
    
        public Integer getCode() {
            return code;
        }
        public void setCode(Integer code) {
            this.code = code;
        }
        public Object getData() {
            return data;
        }
        public void setData(Object data) {
            this.data = data;
        }
        public String getMsg() {
            return msg;
        }
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        @Override
        public String toString() {
            return "JsonData{" +
                    "code=" + code +
                    ", data=" + data +
                    ", msg='" + msg + '\'' +
                    '}';
        }
    }
    

四. Http请求

用于发送请求,访问第三方的 Api 接口,以及解析其中的数据

1. httpclient

Tips:也可以用作解决跨域问题(代理服务器)!

Maven 包管理:

  • 依赖(.pom

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    
1 - 常规请求

url传参

// 图片验证码
// https://www.mxnzp.com/api/verifycode/code?app_secret=申请的id&app_id=申请的id&type=类型(0:图片,1:Base64字节数组)&len=验证码长度
public static ImageVerification getImageVerification(){
    // app_secret
    String appSecret = "申请id";
    // app_id
    String appId = "申请id";
    // 验证码类型
    int type = 0;
    // 验证码长度
    int len = 6;
    // url
    String url = "https://www.mxnzp.com/api/verifycode/code?app_secret=" + appSecret + "&app_id=" + appId + "&type=" + type + "&len=" + len;
    try {
        // 创建一个HttpClient实例
        HttpClient httpClient = HttpClientBuilder.create().build();
        // 创建一个HttpGet请求,指定URL
        HttpGet request = new HttpGet(url);
        // 执行请求,并获取响应
        HttpResponse response = httpClient.execute(request);
        // 将响应实体转换为字符串
        String responseBody = EntityUtils.toString(response.getEntity());
        System.out.println("-----------------图片验证码-----------------");
        System.out.println(responseBody);
        System.out.println("-----------------图片验证码-----------------");
        // 反序列化(把Json串转为JSONObject对象,用于获取指定信息)
        // JSONObject来自于 org.json.JSONObject;包
       	// 例如json格式为:"{"data":"hello","msg","查询成功!","code":123}"
        JSONObject jsonObject = new JSONObject(responseBody);
        // 则可以通过jsonObject.getString("data")获取到hello
        // 还有别的方法(用于获取不同的数据类型):
        // jsonObject.get();
        // jsonObject.getString();
        // jsonObject.getInt();
        // jsonObject.getBoolean();
        // jsonObject.getDouble();
        // jsonObject.getLong();
        String data = jsonObject.getString("data");
        // 转为实体类
        ObjectMapper objectMapper = new ObjectMapper();

        ImageVerification imageVerification = objectMapper.readValue(data, ImageVerification.class);
        System.out.println("图片验证码的密码为:" + imageVerification.getVerifyCode());
        return imageVerification;
    } catch (Exception e) {
        System.err.println("图片验证码获取失败!!!!");
        throw new RuntimeException(e);
    }
}
2 - 设置请求体 / 头

在有时候请求的时候并不能直接用url传参,而是使用post请求来获取信息的话,只能设置请求体或请求头去发送请求

public JsonData sendPhoneCode(String phone) {
    // 创建HttpClient对象
    HttpClient httpClient = HttpClientBuilder.create().build();
    
    // 请求头参数
    String nonce = getRandomNum();
    String curTime = String.valueOf(System.currentTimeMillis());
    String CheckSum = CheckSumBuilder.getCheckSum(APP_SECRET, nonce, curTime);

    // 设置请求头(Header)
    HttpPost httpPost = new HttpPost(url);
	// 请求类型(application/x-www-form-urlencoded表单提交)
    httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
	// 字符编码
    httpPost.setHeader("charset", "utf-8");
	// 其他信息(根据Api提供方添加)
    httpPost.setHeader("AppKey", APP_KEY);
    httpPost.setHeader("Nonce", nonce);
    httpPost.setHeader("CurTime", curTime);
    httpPost.setHeader("CheckSum", checkSum);

    // 创建请求体数据(Body)
    List<NameValuePair> params = new ArrayList<>();
    params.add(new BasicNameValuePair("mobile", phone));
    params.add(new BasicNameValuePair("codeLen", CODE_LEN));
    try {
        httpPost.setEntity(new UrlEncodedFormEntity(params));

        // 发送请求并获取响应
        HttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity = response.getEntity();
        String responseBody = EntityUtils.toString(entity);

        System.out.println("发送验证码结果:" + responseBody);

        JsonData jsonData = new JsonData();
        // 把返回结果解析为键值对从而获取具体的信息
        JSONObject jsonObject = new JSONObject(responseBody);
        // 获取信息
        int code = jsonObject.getInt("code");
        String msg = jsonObject.getString("msg");
        String data = jsonObject.getString("obj");
        // 赋值响应
        jsonData.setCode(code);
        jsonData.setMsg(msg);
        jsonData.setData(data);
        
        return jsonData;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

五. 短信验证码

用于请求第三方服务,发送短信验证码实现登录注册等功能…

1. 网易云信

官网:网易云信 - IM即时通讯云 -音视频通话 (163.com)

20次免费发送的次数

流程需求

需求:

  1. 身份证实名认证(不需要手持身份证)
  2. 环境:jdk 8 - 11 都可以,测试过

流程:

  1. 注册(实名认证)

  2. 登录

  3. 在首页点击 创建应用(填下应用名称、行业类型、应用简介以及应用环境)

    在这里插入图片描述

  4. 创建完成之后点击你的项目名称,进入详情页面(取AppKey

    在这里插入图片描述

  5. 在产品总览里 -> 短信 -> 免费开通(开通下短信服务

    在这里插入图片描述

  6. 开通完之后点击功能配置(查看剩余短信数量...

    在这里插入图片描述

  7. 点击安全配置(可以查看短信默认配置,可以 修改默认配置

    在这里插入图片描述

  8. 功能管理 -> 短信功能管理 -> 国内短信 -> 签名/正文模板管理(获取发送短信的模板

    在这里插入图片描述

  9. 生成发送短信的模板(这个就是你手机上短信的样子

    在这里插入图片描述

  10. 以上创建模板已经完成了,返回到第四步(回到应用首页),去选择 AppKey管理 这一项

    在这里插入图片描述

  11. 获取 AppKeyAppSecret

    在这里插入图片描述

  12. 返回首页 -> 你的项目 -> 产品总览 -> 短信 -> 功能配置 -> 短信功能管理 -> 国内短信开发文档(查看提供发送短信的接口

    在这里插入图片描述

  13. 进来之后有很多接口API,在这里我只说明下两个接口:发送短信已经校验短信正确性

1 - 公共请求头

不管是发送短信还是校验短信都需要设置如下 Header 参数

官方概述:Header 参数为公共请求参数,应用服务端请求云信 IM 服务端,都需在Header 中配置如下参数。

参数参数说明
AppKey通过云信控制台获取,详见[获取 App key](https://doc.yunxin.163.com/docs/Tk5NzkwOTY/TA1ODMzMDc?platformId=50434#获取 App Key) - 上面第11步
Nonce随机数(最大长度 128 个字符) - 可以自己写一个工具类随机生成128为数数字
CurTime当前 UTC 时间戳,从 1970 年 1 月 1 日 0 时 0 分 0 秒开始到 现在(指发起请求瞬间的前后 5 分钟内)的秒数(类型为 String) - 获取当前时间戳
CheckSumSHA1(AppSecret + Nonce + CurTime),将该三个参数拼接的字符串进行 SHA1 哈希计算从而生成 16 进制字符(类型为 String,小写)出于安全性考虑,每个CheckSum有效期5 分钟(用CurTime计算),建议每次请求都生成新的CheckSum,同时请确认发起请求的服务器是与标准时间同步的,比如有NTP服务。CheckSum检验失败时会返回 414 错误码,更多错误码信息请参见状态码。 - 官网提供的工具类
2 - 发送短信

接口介绍:

  • 🔗URL:https://api.netease.im/sms/sendcode.action

请求说明:

POST https://api.netease.im/sms/sendcode.action HTTP/1.1
Content-Type:application/x-www-form-urlencoded;charset=utf-8

接口描述:

向指定的手机号码发送文本短信验证码或语音短信验证码。

参数说明:(设置的请求体)

参数类型必须说明
mobileString目标手机号,非中国大陆手机号码需要填写国家代码(如美国:+1-xxxxxxxxxx)或地区代码(如香港:+852-xxxxxxxx)
deviceIdString目标设备号,可选参数
templateidint模板编号(如不指定则使用配置的默认模版)
codeLenint验证码长度,默认为 4 位,取值范围为 4-10 (注:语音验证码的取值范围为 4-8位)。
authCodeString客户自定义验证码,长度为 4 ~ 10 位,支持字母和数字。 如果设置了该参数,则codeLen参数无效
needUpBoolean是否需要支持短信上行。true:需要,false:不需要 说明:如果开通了短信上行抄送功能,该参数需要设置为true,其它情况设置无效

请求示例:

curl -X POST -H "AppKey: go9dnk49bkd9jd9vmel1kglw0803mgq3" -H "CurTime: 1443592222" -H "CheckSum: 9e9db3b6c9abb2e1962cf3e6f7316fcc55583f86" -H "Nonce: 4tgggergigwow323t23t" -H "Content-Type: application/x-www-form-urlencoded" -d 'mobile=13812345678' 'https://api.netease.im/sms/sendcode.action'

返回说明:

http 响应:json

发送成功则返回相关信息。msg字段表示此次发送的sendid;obj字段表示此次发送的验证码。

"Content-Type": "application/json; charset=utf-8"
{
  "code": 200,
  "msg": "88",
  "obj": "1908"
}
3 - 校验短信

接口介绍:

  • 🔗URL:https://api.netease.im/sms/verifycode.action

请求说明:

POST https://api.netease.im/sms/verifycode.action HTTP/1.1
Content-Type:application/x-www-form-urlencoded;charset=utf-8

接口描述:

校验指定手机号的验证码是否合法。

参数说明:(设置的请求体)

参数类型必须说明
mobileString目标手机号,非中国大陆手机号码需要填写国家代码(如美国:+1-xxxxxxxxxx)或地区代码(如香港:+852-xxxxxxxx)
codeString验证码

curl请求示例

curl -X POST -H "AppKey: go9dnk49bkd9jd9vmel1kglw0803mgq3" -H "CurTime: 1443592222" -H "CheckSum: 9e9db3b6c9abb2e1962cf3e6f7316fcc55583f86" -H "Nonce: 4tgggergigwow323t23t" -H "Content-Type: application/x-www-form-urlencoded" -d 'mobile=13812345678&code=1234' 'https://api.netease.im/sms/verifycode.action'

返回说明

http 响应:json

"Content-Type": "application/json; charset=utf-8"
{
  "code":200
}
4 - 返回常用状态码

200、301、315、403、404、413、414、500

具体请参考code状态表

5 - 工具类

以下为发送验证码 - 5分钟有效期并同一手机号60秒内不能重复发送请求

Java开发环境

  • 依赖(.pom):

    <!-- 发送http请求 -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>
    <!-- Redis操作 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
        <version>2.5.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>2.5.5</version>
    </dependency>
    

发送验证码与校验验证码

package project.pet.util.sms.eleven;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import project.pet.util.JsonData;
import project.pet.util.MyUtil;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 全 POST 请求
 * <p>
 * 接码平台:https://app.yunxin.163.com/global/home
 * 参数:
 * 1. AppKey:你的key
 * 2. AppSecret:你的key
 * 请求头:
 * 1. Content-Type:application/x-www-form-urlencoded
 * 2. charset:utf-8
 * 3. AppKey:网站提供
 * 4. Nonce:随机的 1 - 128 位随机数
 * 5. CurTime:当前时间戳
 * 6. CheckSum:AppSecret + Nonce + CurTime 组合的SHA1加密密文
 * 请求体:
 * 1. mobile:目标手机号码(收短信的人儿)
 * 2. codeLen:短信验证码的长度(4-10位!)
 * 3. code:校验的验证码(校验接口使用)
 * 接口:
 * 1. 发送验证码:https://api.netease.im/sms/sendcode.action
 * 2. 校验验证码:https://api.netease.im/sms/verifycode.action
 * Tips:
 * 写的肥肠详细,短信数量没有了就去申请,一个人20条
 */
@Component
public class SendPhoneCode {
    // AppKey
    private final String APP_KEY = "你的key";
    // AppSecret
    private final String APP_SECRET = "你的key";
    // 验证码位数
    private final String CODE_LEN = String.valueOf(6);
    // Redis操作
    @Autowired
    private RedisTemplate redisTemplate;

    public JsonData sendPhoneCode(String phone) {
        // 手机号码验证
        if (!MyUtil.isValidPhoneNumber(phone)){
            return JsonData.buildError("手机号码格式不合法!");
        }
        // 创建HttpClient对象
        HttpClient httpClient = HttpClientBuilder.create().build();

        // 请求头参数
        String nonce = getRandomNum();
        String curTime = String.valueOf(System.currentTimeMillis());
        String CheckSum = CheckSumBuilder.getCheckSum(APP_SECRET, nonce, curTime);

        // 获取剩余时间(以秒为单位)
        Long remainingTime = redisTemplate.getExpire("smsCode:" + phone, TimeUnit.SECONDS);
        // 用来实现对同一手机号60秒内不能发送多次请求获取验证码
        if (remainingTime >= 240) {
            return JsonData.buildCodeAndMsg(444, "60秒内只能请求一次,请待会儿再来!");
        }

        // 设置请求头
        HttpPost httpPost = createHttpPost("https://api.netease.im/sms/sendcode.action", nonce, curTime, CheckSum);

        // 创建请求体数据
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("mobile", phone));
        params.add(new BasicNameValuePair("codeLen", CODE_LEN));
        try {
            httpPost.setEntity(new UrlEncodedFormEntity(params));

            // 发送请求并获取响应
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            String responseBody = EntityUtils.toString(entity);

            System.out.println("发送验证码结果:" + responseBody);

            JsonData jsonData = new JsonData();
            // 把返回结果解析为键值对从而获取具体的信息
            JSONObject jsonObject = new JSONObject(responseBody);
            // 获取信息
            int code = jsonObject.getInt("code");
            String msg = jsonObject.getString("msg");
            String data = jsonObject.getString("obj");
            // 赋值响应
            jsonData.setCode(code);
            jsonData.setMsg(msg);
            jsonData.setData(data);
            // 存储到缓存中(必须找个地方存下,校验的时候需要取出来进行合成CheckSum来校验)
            redisTemplate.opsForHash().put("smsCode:" + phone, "nonce", nonce);
            redisTemplate.opsForHash().put("smsCode:" + phone, "curTime", curTime);
            redisTemplate.opsForHash().put("smsCode:" + phone, "CheckSum", CheckSum);
            // 存储验证码
            redisTemplate.opsForHash().put("smsCode:" + phone, "code", data);
            // 设置过期时间,标识(60s内重复请求)
            redisTemplate.expire("smsCode:" + phone, 300, TimeUnit.SECONDS);

            return jsonData;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public JsonData checkPhoneCode(String phone, String code) {
        // 创建HttpClient对象
        HttpClient httpClient = HttpClientBuilder.create().build();

        // 创建HttpPost对象,设置URL

        // 从缓存中获取值
        Map<String, Object> entries = redisTemplate.opsForHash().entries("smsCode:" + phone);
        if (entries.size() == 0) {
            return JsonData.buildCodeAndMsg(404, "验证码已过期请重新发送!");
        }
        if (!entries.get("code").equals(code)) {
            return JsonData.buildCodeAndMsg(413, "验证码有误请重新输入!");
        }

        // 请求头参数
        String nonce = (String) entries.get("nonce");
        String curTime = (String) entries.get("curTime");
        String CheckSum = (String) entries.get("CheckSum");

        // 设置请求头
        HttpPost httpPost = createHttpPost("https://api.netease.im/sms/verifycode.action", nonce, curTime, CheckSum);

        // 创建请求体数据
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("mobile", phone));
        params.add(new BasicNameValuePair("code", code));
        try {

            httpPost.setEntity(new UrlEncodedFormEntity(params));

            // 发送请求并获取响应
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            String responseBody = EntityUtils.toString(entity);

            System.out.println("校验验证码发送结果:" + responseBody);

            JsonData jsonData = new JsonData();
            JSONObject jsonObject = new JSONObject(responseBody);
            int returnCode = jsonObject.getInt("code");
            jsonData.setCode(returnCode);
            if (returnCode!= 200){
                jsonData.setMsg("验证码校验失败!");
                jsonData.setData(jsonObject.getString("obj"));
                return jsonData;
            }
            jsonData.setMsg("验证码正确!");
            System.out.println("校验验证码结果:" + responseBody);
            return jsonData;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    // 设置公共请求头
    private HttpPost createHttpPost(String url,String nonce,String curTime,String checkSum){
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
        httpPost.setHeader("charset", "utf-8");
        httpPost.setHeader("AppKey", APP_KEY);
        httpPost.setHeader("Nonce", nonce);
        httpPost.setHeader("CurTime", curTime);
        httpPost.setHeader("CheckSum", checkSum);
        return httpPost;
    }
    
    // 生成1-128之间的随机长度(用于生成公共请求头参数的Nonce)
    private String getRandomNum() {
        int length = new Random().nextInt(128) + 1;
        StringBuilder sb = new StringBuilder();

        String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();

        for (int i = 0; i < length; i++) {
            int index = random.nextInt(characters.length());
            char randomChar = characters.charAt(index);
            sb.append(randomChar);
        }

        return sb.toString();
    }
}

// 其中的JsonData为同一返回数据格式(在上面的笔记中可以找到)
// MyUtil为自己写的工具类

生成CheckSum的工具类(官方提供)

package project.pet.util.sms.eleven;

import java.security.MessageDigest;

public class CheckSumBuilder {
    // 计算并获取CheckSum
    public static String getCheckSum(String appSecret, String nonce, String curTime) {
        return encode("sha1", appSecret + nonce + curTime);
    }

    // 计算并获取md5值
    public static String getMD5(String requestBody) {
        return encode("md5", requestBody);
    }

    private static String encode(String algorithm, String value) {
        if (value == null) {
            return null;
        }
        try {
            MessageDigest messageDigest
                    = MessageDigest.getInstance(algorithm);
            messageDigest.update(value.getBytes());
            return getFormattedText(messageDigest.digest());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    private static String getFormattedText(byte[] bytes) {
        int len = bytes.length;
        StringBuilder buf = new StringBuilder(len * 2);
        for (int j = 0; j < len; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
            buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
        }
        return buf.toString();
    }
    private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值