unity前端通过java后端实现短信验证码登录

2023-11-11

一、搭建java后端

 1、新建一个springboot项目,初始导入spring-boot-starter-data-redis,spring-boot-starter-data-web,lombok依赖

2、进入阿里巴巴短信运营商购买短信服务,记住AppCode。

  【体验价0.013】三网短信接口-短信验证码-通知短信-短信验证码-三网短信接口-短信通知-短信验证码-验证码短信-短信接口【最新版】_商业智能_电商_金融-云市场-阿里云


往下拉会有短信接口示例

public static void main(String[] args) {
	    String host = "https://dfsns.market.alicloudapi.com";
	    String path = "/data/send_sms";
	    String method = "POST";
	    String appcode = "你自己的AppCode";
	    Map<String, String> headers = new HashMap<String, String>();
	    //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
	    headers.put("Authorization", "APPCODE " + appcode);
	    //根据API的要求,定义相对应的Content-Type
	    headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
	    Map<String, String> querys = new HashMap<String, String>();
	    Map<String, String> bodys = new HashMap<String, String>();
	    bodys.put("content", "code:1234");
	    bodys.put("phone_number", "156*****140");
	    bodys.put("template_id", "TPL_0000");


	    try {
	    	/**
	    	* 重要提示如下:
	    	* HttpUtils请从
	    	* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/src/main/java/com/aliyun/api/gateway/demo/util/HttpUtils.java
	    	* 下载
	    	*
	    	* 相应的依赖请参照
	    	* https://github.com/aliyun/api-gateway-demo-sign-java/blob/master/pom.xml
	    	*/
	    	HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
	    	System.out.println(response.toString());
	    	//获取response的body
	    	//System.out.println(EntityUtils.toString(response.getEntity()));
	    } catch (Exception e) {
	    	e.printStackTrace();
	    }
	}

打开api-gateway-demo-sign-java/pom.xml at master · aliyun/api-gateway-demo-sign-java · GitHub,将相关依赖导入springBoot中,

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

<!--        fastJson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.79</version>
        </dependency>
        <!--mp-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <!--mysql连接-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <!--        http的各种状态码-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.15</version>
            <scope>compile</scope>
        </dependency>

<!--        apacha提供的工具类-->
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
            <scope>compile</scope>
        </dependency>

<!--        http工具包-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

api-gateway-demo-sign-java/HttpUtils.java at master · aliyun/api-gateway-demo-sign-java · GitHub将HttpUtils.java放入项目中的utils包中

import org.apache.commons.lang.StringUtils;
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.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class HttpUtils {

    /**
     * get
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @return
     * @throws Exception
     */
    public static HttpResponse doGet(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpGet request = new HttpGet(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        return httpClient.execute(request);
    }

    /**
     * post form
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param bodys
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      Map<String, String> bodys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (bodys != null) {
            List<NameValuePair> nameValuePairList = new ArrayList<NameValuePair>();

            for (String key : bodys.keySet()) {
                nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key)));
            }
            UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8");
            formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8");
            request.setEntity(formEntity);
        }

        return httpClient.execute(request);
    }

    /**
     * Post String
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      String body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (StringUtils.isNotBlank(body)) {
            request.setEntity(new StringEntity(body, "utf-8"));
        }

        return httpClient.execute(request);
    }

    /**
     * Post stream
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPost(String host, String path, String method,
                                      Map<String, String> headers,
                                      Map<String, String> querys,
                                      byte[] body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPost request = new HttpPost(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (body != null) {
            request.setEntity(new ByteArrayEntity(body));
        }

        return httpClient.execute(request);
    }

    /**
     * Put String
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPut(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys,
                                     String body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPut request = new HttpPut(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (StringUtils.isNotBlank(body)) {
            request.setEntity(new StringEntity(body, "utf-8"));
        }

        return httpClient.execute(request);
    }

    /**
     * Put stream
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @param body
     * @return
     * @throws Exception
     */
    public static HttpResponse doPut(String host, String path, String method,
                                     Map<String, String> headers,
                                     Map<String, String> querys,
                                     byte[] body)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpPut request = new HttpPut(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        if (body != null) {
            request.setEntity(new ByteArrayEntity(body));
        }

        return httpClient.execute(request);
    }

    /**
     * Delete
     *
     * @param host
     * @param path
     * @param method
     * @param headers
     * @param querys
     * @return
     * @throws Exception
     */
    public static HttpResponse doDelete(String host, String path, String method,
                                        Map<String, String> headers,
                                        Map<String, String> querys)
            throws Exception {
        HttpClient httpClient = wrapClient(host);

        HttpDelete request = new HttpDelete(buildUrl(host, path, querys));
        for (Map.Entry<String, String> e : headers.entrySet()) {
            request.addHeader(e.getKey(), e.getValue());
        }

        return httpClient.execute(request);
    }

    private static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
        StringBuilder sbUrl = new StringBuilder();
        sbUrl.append(host);
        if (!StringUtils.isBlank(path)) {
            sbUrl.append(path);
        }
        if (null != querys) {
            StringBuilder sbQuery = new StringBuilder();
            for (Map.Entry<String, String> query : querys.entrySet()) {
                if (0 < sbQuery.length()) {
                    sbQuery.append("&");
                }
                if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
                    sbQuery.append(query.getValue());
                }
                if (!StringUtils.isBlank(query.getKey())) {
                    sbQuery.append(query.getKey());
                    if (!StringUtils.isBlank(query.getValue())) {
                        sbQuery.append("=");
                        sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
                    }
                }
            }
            if (0 < sbQuery.length()) {
                sbUrl.append("?").append(sbQuery);
            }
        }

        return sbUrl.toString();
    }

    private static HttpClient wrapClient(String host) {
        HttpClient httpClient = new DefaultHttpClient();
        if (host.startsWith("https://")) {
            sslClient(httpClient);
        }

        return httpClient;
    }

    private static void sslClient(HttpClient httpClient) {
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(X509Certificate[] xcs, String str) {

                }
                public void checkServerTrusted(X509Certificate[] xcs, String str) {

                }
            };
            ctx.init(null, new TrustManager[] { tm }, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = httpClient.getConnectionManager();
            SchemeRegistry registry = ccm.getSchemeRegistry();
            registry.register(new Scheme("https", 443, ssf));
        } catch (KeyManagementException ex) {
            throw new RuntimeException(ex);
        } catch (NoSuchAlgorithmException ex) {
            throw new RuntimeException(ex);
        }
    }
}

3、将统一返回结果R放入utlis包中

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.http.HttpStatus;

import java.util.HashMap;
import java.util.Map;

/**
 * 返回数据
 */
public class R extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;
	public R setData(Object data){
		put("data",data);
		return this;
	}

	public <T> T getData(TypeReference<T> typeReference){
		Object data = get("data");
		String jsonString = JSON.toJSONString(data);
		T t = JSON.parseObject(jsonString, typeReference);
		return t;
	}
	public <T> T getData(String key,TypeReference<T> typeReference){
		Object data = get(key);
		String jsonString = JSON.toJSONString(data);
		T t = JSON.parseObject(jsonString, typeReference);
		return t;
	}
	public R() {
		put("code", 0);
		put("msg", "success");
	}
	
	public static R error() {
		return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
	}
	
	public static R error(String msg) {
		return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
	}
	
	public static R error(int code, String msg) {
		R r = new R();
		r.put("code", code);
		r.put("msg", msg);
		return r;
	}

	public static R ok(String msg) {
		R r = new R();
		r.put("msg", msg);
		return r;
	}
	
	public static R ok(Map<String, Object> map) {
		R r = new R();
		r.putAll(map);
		return r;
	}
	
	public static R ok() {
		return new R();
	}
	public Integer getCode(){
		return  (Integer) this.get("code");
	}

	@Override
	public R put(String key, Object value) {
		super.put(key, value);
		return this;
	}
}

4、将随机生成验证码工具类ValidateCodeUtils放入utils包中

import java.util.Random;

/**
 * 随机生成验证码工具类
 * @author superman
 */
public class ValidateCodeUtils {
    /**
     * 随机生成验证码
     * @param length 长度为4位或者6位
     * @return
     */
    public static Integer generateValidateCode(int length){
        Integer code =null;
        if(length == 4){
            //生成随机数,最大为9999
            code = new Random().nextInt(9999);
            if(code < 1000){
                //保证随机数为4位数字
                code = code + 1000;
            }
        }else if(length == 6){
            //生成随机数,最大为999999
            code = new Random().nextInt(999999);
            if(code < 100000){
                //保证随机数为6位数字
                code = code + 100000;
            }
        }else{
            throw new RuntimeException("只能生成4位或6位数字验证码");
        }
        return code;
    }

    /**
     * 随机生成指定长度字符串验证码
     * @param length 长度
     * @return
     */
    public static String generateValidateCode4String(int length){
        Random rdm = new Random();
        String hash1 = Integer.toHexString(rdm.nextInt());
        String capstr = hash1.substring(0, length);
        return capstr;
    }
}

5、自定义一个缓存key的前缀SMSConstant类放入constant包中

public class SMSConstant {
    public static final String SMS_CODE_CACHE_PREFIX="sms:code:";
}

6、在application.yml文件中配置redis的相关配置与端口号

spring:
  redis:
    password: 123321
    host: 127.0.0.1
    port: 6379
    database: 0
server:
  port: 8888

7、定义service接口LoginService 

/**
 * @author superman
 */
public interface LoginService {

    /**
     * 像手机发送验证码
     * @param phone 手机号
     * @param code 验证码
     */
    void sendCode(String phone,String code);
}

8、定义该接口的实现类LoginServiceImpl 

import com.liulala.service.LoginService;
import com.liulala.utils.HttpUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
public class LoginServiceImpl implements LoginService {
    private String host ="https://dfsns.market.alicloudapi.com";
    private String path  ="/data/send_sms";
    private String templateId  = "TPL_0000";
    private String appcode  = "第2步中的appcode码";
    @Override
    public void sendCode(String phone, String code) {

            String method = "POST";
            Map<String, String> headers = new HashMap<>();
            //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
            headers.put("Authorization", "APPCODE " + appcode);
            //根据API的要求,定义相对应的Content-Type
            headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
            Map<String, String> querys = new HashMap<>();
            Map<String, String> bodys = new HashMap<>();
            bodys.put("content", "code:"+code);
            bodys.put("phone_number", phone);
            bodys.put("template_id", templateId);
            try {
                HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
                //获取response的body
                System.out.println(EntityUtils.toString(response.getEntity()));
            } catch (Exception e) {
                e.printStackTrace();
            }

    }
}

9、定义LoginController类

import com.liulala.constant.SMSConstant;
import com.liulala.service.LoginService;
import com.liulala.utils.R;
import com.liulala.utils.ValidateCodeUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.TimeUnit;

@RestController
public class LoginController {
    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    LoginService loginService;

    @GetMapping("/sms/sendCode")
    public R sendCode(@RequestParam("phone") String phone) {
      //1、从redis中获取该手机号存储的验证码
        String redisCode = redisTemplate.opsForValue().get(SMSConstant.SMS_CODE_CACHE_PREFIX + phone);
        //如果存储过验证码,并且当前次验证码与上一次验证码时间间隔小于60s,则返回
        if (StringUtils.isNotEmpty(redisCode)) {
            //获取上次验证码发送时的时间
            long time = Long.parseLong(redisCode.split("_")[1]);
            //如果该两次验证码发送间隔小于60s
            if (System.currentTimeMillis() - time < 60 * 1000) {
                //60s内不能再刷
                return R.error(10002, "短信发送频率过快,请稍后再试");
            }
        }
        //2、如果第一次发送验证码或者两次验证码间隔时间超过60s,则生成一个验证码,将验证码与生成验证码的时间拼为一个新字符串
        String code = ValidateCodeUtils.generateValidateCode(4).toString()+"_" + System.currentTimeMillis();
        //3、将验证码存储到缓存中,key为设定的前缀+手机号,值为验证码+生成验证码的时间(用于接口防刷),10分钟后过期删除验证码
        redisTemplate.opsForValue().set(SMSConstant.SMS_CODE_CACHE_PREFIX + phone, code, 10, TimeUnit.MINUTES);
        //4、将验证码发送给手机
        loginService.sendCode(phone,code.split("_")[0]);
        return R.ok();
    }

    /**
     * 登录
     * @param phone
     * @param code
     * @return
     */
    @GetMapping("/login")
    public R login(@RequestParam("phone") String phone,@RequestParam("code") String code){
        //登录,从redis中获取验证码
        String redisCode = redisTemplate.opsForValue().get(SMSConstant.SMS_CODE_CACHE_PREFIX +phone);
        if(StringUtils.isNotEmpty(redisCode)){
            if(code.equals(redisCode.split("_")[0])){
                //匹配成功,删除验证码
                redisTemplate.delete(SMSConstant.SMS_CODE_CACHE_PREFIX +phone);
                return R.ok();
            }
        }
        return R.error(10003,"验证码错误");
    }
}

10、主启动程序排除数据库相关依赖,

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class TestSmsApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestSmsApplication.class, args);
    }

}

后端功能完成,

项目结构为

 二:搭建unity前端

1、编写脚本LoginController,将脚本挂在任一物体上,这里挂在主相机上

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class LoginController : MonoBehaviour
{
    
    public Text phone;
    public Text code;
    public Text resultText;
  
   
    // Update is called once per frame
    void Update()
    {        
    }
    //验证码登录
    public void Login() {
        StartCoroutine(CodeUserLogin(phone.text, code.text));
    }
    //发送短信验证码
    public void SendCode() {
        StartCoroutine(SendPhoneCode(phone.text));
    }
    
    //登录验证短信验证码
    IEnumerator CodeUserLogin(string phone, string code)
    {
        UnityWebRequest unityWebRequest = UnityWebRequest.Get("http://localhost:8888/login?phone=" + phone+"&code="+code); //创建UnityWebRequest对象
        yield return unityWebRequest.SendWebRequest(); //等待返回请求的信息
        if (unityWebRequest.result == UnityWebRequest.Result.ProtocolError ||
            unityWebRequest.result == UnityWebRequest.Result.ConnectionError) //如果其 请求失败,或是 网络错误
        {
            Debug.Log(unityWebRequest.error); //打印错误原因
        }
        else //请求成功
        {
            //如果访问的链接有返回文本结果,比如json文本,则通过text获取
            string result = unityWebRequest.downloadHandler.text;
            var r = JsonUtility.FromJson<R>(result);
            //将后端返回结果显示在UI
            print(r.msg);
            resultText.text = r.msg;
            if (r.code == 0) {
                Debug.Log("登录成功");
                resultText.text = "登录成功";
            }
        }
    }

    //发送短信验证码到手机
    IEnumerator SendPhoneCode(string phone)
    {
        UnityWebRequest unityWebRequest = UnityWebRequest.Get("http://localhost:8888/sms/sendCode?phone="+phone); //创建UnityWebRequest对象
        yield return unityWebRequest.SendWebRequest(); 
        if (unityWebRequest.result == UnityWebRequest.Result.ProtocolError ||
            unityWebRequest.result == UnityWebRequest.Result.ConnectionError) 
        {
            Debug.Log(unityWebRequest.error); //打印错误原因
        }
        else //请求成功
        {          
            string result = unityWebRequest.downloadHandler.text;
            var r = JsonUtility.FromJson<R>(result);
            print(r.msg);
            //将后端返回结果显示在UI
            resultText.text = r.msg;
            if (r.code == 0)
            {
                Debug.Log("发送验证码成功");
                resultText.text = "成功发送验证码";
            }
        }
    }
}
[Serializable]
class R
{
    public int code;
    public string msg;
  
    public R()
    {
    }
    override
    public string ToString()
    {
        return "code:" + code + ",msg" + msg;
    }
}

2、创建一个scene,scene中创建2个inputField,2个button,1个显示结果的resultText,挂载响应的text

3、sendCodeButton绑定单击事件LoginController中的 sendCode方法

   loginButton绑定单击事件LoginController中的Login方法

4、启动后台与unity进行测试,

       输入手机号,点击发送验证码,手机收到验证码,redis中会存储相应的验证码,过期时间10分钟,验证码输入,验证通过后删除掉该验证码

1分钟内再次点击发送验证码

 输入错误验证码

 输入正确验证码,redis中保存的验证码会被清除

5、后续需要完善的功能:

     1)添加前端与后端的手机号的正则验证,

      2)通过手机号去数据库中查询用户信息,若未查到,则创建用户并保存在数据库中

      3)将用户信息作为value,生成一个随机token值作为key保存在redis中,

      4)将token值返回给前端,

      5)untiy前端通过UnityWebRequest的SetRequestHeader方法设置请求头,需要token验证的请求可以将token放在请求头中来访问。

       6)后端添加一个拦截器,拦截前端每一次请求的请求头中 的token

       7)若token不为空,并且能通过token从redis中查到用户信息,则将用户信息存储在threadlocal中,其他类需要用户信息从threadlocal中获取

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

unity前端通过java后端实现短信验证码登录 的相关文章

  • 在 Java 中克隆对象 [3 个问题]

    这样做会调用Asub的clone方法吗 或者Asub深度克隆是否正确 如果没有的话 有没有办法通过这种方法对Asub进行深度克隆呢 abstract class Top extends TopMost protected Object cl
  • 不同帐户上的 Spring Boot、JmsListener 和 SQS 队列

    我正在尝试开发一个 Spring Boot 1 5 应用程序 该应用程序需要侦听来自两个不同 AWS 帐户的 SQS 队列 是否可以使用 JmsListener 注解创建监听器 我已检查权限是否正确 我可以使用 getQueueUrl 获取
  • 在内存中使用 byte[] 创建 zip 文件。 Zip 文件总是损坏

    我创建的 zip 文件有问题 我正在使用 Java 7 我尝试从字节数组创建一个 zip 文件 其中包含两个或多个 Excel 文件 应用程序始终完成 没有任何异常 所以 我以为一切都好 当我尝试打开 zip 文件后 Windows 7 出
  • 动态选择端口号?

    在 Java 中 我需要获取端口号以在同一程序的多个实例之间进行通信 现在 我可以简单地选择一些固定的数字并使用它 但我想知道是否有一种方法可以动态选择端口号 这样我就不必打扰我的用户设置端口号 这是我的一个想法 其工作原理如下 有一个固定
  • 如何获取之前的URL?

    我需要调用我的网络应用程序的 URL 例如 如果有一个从 stackoverflow com 到我的网站 foo com 的链接 我需要 Web 应用程序 托管 bean 中的 stackoverflow 链接 感谢所有帮助 谢谢 并不总是
  • 在 Jar 文件中运行 ANT build.xml 文件

    我需要使用存储在 jar 文件中的 build xml 文件运行 ANT 构建 该 jar 文件在类路径中可用 是否可以在不分解 jar 文件并将 build xml 保存到本地目录的情况下做到这一点 如果是的话我该怎么办呢 Update
  • 如何更改javaFX中按钮的图像?

    我正在使用javaFX 我制作了一个按钮并为此设置了图像 代码是 Image playI new Image file c Users Farhad Desktop icons play2 jpg ImageView iv1 new Ima
  • 来自 dll 的 Java 调用函数

    我有这个 python 脚本导入zkemkeeperdll 并连接到考勤设备 ZKTeco 这是我正在使用的脚本 from win32com client import Dispatch zk Dispatch zkemkeeper ZKE
  • 从最终实体获取根证书和中间证书

    作为密码学的菜鸟 我每天都会偶然发现一些简单的事情 今天只是那些日子之一 我想用 bouncy castle 库验证 java 中的 smime 消息 我想我几乎已经弄清楚了 但此时的问题是 PKIXparameters 对象的构建 假设我
  • 将 MOXy 设置为 JAXB 提供程序,而在同一包中没有属性文件

    我正在尝试使用 MOXy 作为我的 JAXB 提供程序 以便将内容编组 解组到 XML JSON 中 我创建了 jaxb properties 文件 内容如下 javax xml bind context factory org eclip
  • 在 junit 测试中获取 javax.lang.model.element.Element 类

    我想测试我的实用程序类 ElementUtils 但我不知道如何将类作为元素获取 在 AnnotationProcessors 中 我使用以下代码获取元素 Set
  • 如何在用户输入数据后重新运行java代码

    嘿 我有一个基本的java 应用程序 显示人们是成年人还是青少年等 我从java开始 在用户输入年龄和字符串后我找不到如何制作它它们被归类为 我希望它重新运行整个过程 以便其他人可以尝试 的节目 我一直在考虑做一个循环 但这对我来说没有用
  • 如何在谷歌地图android上显示多个标记

    我想在谷歌地图android上显示带有多个标记的位置 问题是当我运行我的应用程序时 它只显示一个位置 标记 这是我的代码 public class koordinatTask extends AsyncTask
  • 使用 AsyncTask 传递值

    我一直在努力解决这个问题 但我已经到了不知道该怎么办的地步 我想做的是使用一个类下载文件并将其解析为字符串 然后将该字符串发送到另一个类来解析 JSON 内容 所有部件都可以单独工作 并且我已经单独测试了所有部件 我只是不知道如何将值发送到
  • 专门针对 JSP 的测试驱动开发

    在理解 TDD 到底是什么之前 我就已经开始编写测试驱动的代码了 在没有实现的情况下调用函数和类可以帮助我以更快 更有效的方式理解和构建我的应用程序 所以我非常习惯编写代码 gt 编译它 gt 看到它失败 gt 通过构建其实现来修复它的过程
  • 最新的 Hibernate 和 Derby:无法建立 JDBC 连接

    我正在尝试创建一个使用 Hibernate 连接到 Derby 数据库的准系统项目 我正在使用 Hibernate 和 Derby 的最新版本 但我得到的是通用的Unable to make JDBC Connection error 这是
  • Opencv Java 灰度

    我编写了以下程序 尝试从彩色转换为灰度 Mat newImage Imgcodecs imread q1 jpg Mat image new Mat new Size newImage cols newImage rows CvType C
  • 如何使用mockito模拟构建器

    我有一个建造者 class Builder private String name private String address public Builder setName String name this name name retur
  • 使用反射覆盖最终静态字段是否有限制?

    在我的一些单元测试中 我在最终静态字段上的反射中遇到了奇怪的行为 下面是说明我的问题的示例 我有一个基本的 Singleton 类 其中包含一个 Integer public class BasicHolder private static
  • 双枢轴快速排序和快速排序有什么区别?

    我以前从未见过双枢轴快速排序 是快速排序的升级版吗 双枢轴快速排序和快速排序有什么区别 我在 Java 文档中找到了这个 排序算法是双枢轴快速排序 作者 弗拉基米尔 雅罗斯拉夫斯基 乔恩 本特利和约书亚 布洛赫 这个算法 在许多数据集上提供

随机推荐

  • 正态性检验ks和sw区别_非参数检验思路总结,清晰理解就靠它了!

    1 何时使用非参数检验 或许你还没有理解什么是参数检验 非参数检验 但一定曾在无意之中使用过它们 如我们常用的方差分析 T检验 都属于参数检验 参数检验 就是假定数据服从某种分布 通过样本信息对总体参数进行检验 因而在分析前 先要检验数据是
  • libghttp的使用

    libghttp的使用 前言 一 libghttp是什么 二 使用步骤 1 引入库 前言 需要使用get请求来获得点数据 但是由于需要用户名和密码 所以失败了 但是编译的过程还有其他还是有参考价值的 一 libghttp是什么 官方网站ht
  • 华为OD机试真题 Java 实现【最长子字符串的长度】【2022Q4 100分】,附详细解题思路

    目录 专栏导读 一 题目描述 二 输入描述 三 输出描述 四 解题思路 解题思路如下 解题思路分析 五 Java算法源码 六 效果展示 1 输入 2 输出 3 说明 华为OD机试 2023B卷题库疯狂收录中 刷题点这里 专栏导读 一 题目描
  • 代码质量检测(三)—— SonarLint和SonarQube的本地使用

    根据 代码质量检测 一 常用代码质量管理工具 的介绍和 代码质量检测 二 如何选择代码检查工具 的分析 我们大概得出结论 在当前开源的代码质量检测工具中 阿里系列除外 pmd 基于源代码分析 主要面向安全编码规则 如 避免声明同名变量 包括
  • ​​PMP项目管理—第6章 项目进度管理。

    PMBOK项目管理知识体系指南 PMP项目管理学习笔记 总 第1章 引论 第2章 项目运行环境 第3章 项目经理的角色 第4章 项目整合管理 第5章 项目范围管理 第6章 项目进度管理 第7章 项目成本管理 第8章 项目质量管理 第9章 项
  • Ubuntu搭建Git仓库

    Ubuntu中搭建Git仓库 简介 这里使用的是阿里的Ubuntu服务器进行Git仓库搭建 Git在个人服务器搭建不适合新手 需要一定基础 安装Git 首先登录服务器 使用 以下命令安装Git sudo apt get install gi
  • 粉丝破千了,喊几个机器人跳个舞庆祝下

    先看效果 机器人跳舞 再看代码
  • js获取视频时长

    p p
  • php 混淆 js,通过php实现对js的加密混淆

    使用php对js进行混淆加密 具体方法如下 js路径 jsPath DIR assets js 不需要压缩的JS exclude array jQuery ui position min js easy validator pack js
  • CentOS7 yum安装mysql5.7,查看默认root密码

    CentOS7默认安装MariaDB 安装mysql5 7就需要添加mysql官方yum源 1 下载官方yum源 首先需要下载官方yum源 wget https repo mysql com mysql57 community releas
  • 解决页面中引用了谷歌字体库访问缓慢的问题

    解决页面中引用了谷歌字体库访问缓慢的问题 这段时间做一个项目的时候遇到了页面访问谷歌字体库加载缓慢的问题 因为引用了别人的页面模板 其中需要使用到谷歌字体也就是 但是为了开发和调试的方便 设置了浏览器禁止缓存 每次刷新页面非常缓慢 从chr
  • java基础详解1----package引入&CLASSPATH

    一 对于公共类 public java源码文件名一定要与类名一致 否则会报错 D project helloWorld gt javac hello java hello java 1 错误 类HelloWorld是公共的 应在名为 Hel
  • Visio 2010 软件:安装即可使用

    安装方法 此文件位Visio 2010 光盘镜像文件 点击打开直接安装 关注下方微信公众号 免费获取海量电子书资源 关注公众号 点击电子书 获取下载链接
  • flutter 修改host文件

    找地址 11 打开 https www ipaddress com 输入访问不了的域名 1 通过网站查网站ip地址 网上有很多网站可以查询网站的ip地址 这里推荐一个好的查询网站ip地址的网站 就是https www wanshangdat
  • extends与implements的使用和区别

    extends 是继承父类 只要那个类不是声明final或者定义为abstract就能继承 JAVA中不支持多重继承 继承只能继承一个类 但implements可以实现多个接口 用逗号分开就行了 比如 class A extends B i
  • datagrid动态更改属性值:如单选多选

    if staffName indexOf sendstaff 0 grid datagrid singleSelect true else grid datagrid singleSelect false
  • VScode User Settings

    1 How to find setting file gt preference gt setting 2 find the settings json 3 pay attention to the character after each
  • Java中通过NetworkInterface获取主机地址和物理地址等

    场景 Networklnterface类表示一个由名称和分配给此接口的IP地址列表组成的网络接口 也 就是Networklnterface类包含网络接口名称与IP地址列表 该类提供访问网卡设备的相关 信息 如可以获取网卡名称 IP地址和子网
  • sar命令

    sar 使用举例 1 输出CPU使用情况的统计信息 2 显示I O和传送速率的统计信息 3 输出内存页面的统计信息 4 输出每秒创建的进程数的进程统计信息 5 输出网络设备状态的统计信息 6 输出网络设备状态的统计信息 查看网络设备故障 7
  • unity前端通过java后端实现短信验证码登录

    一 搭建java后端 1 新建一个springboot项目 初始导入spring boot starter data redis spring boot starter data web lombok依赖 2 进入阿里巴巴短信运营商购买短信