说明:微信扫描登录需要微信注册--要钱,感谢尚硅谷提供的免费接口;短信注册需要阿里云的注册很麻烦并且短信费,没有接口,所以不打算实现,不过能做出效果。
目录
一、建立数据库
二、后端idea实现接口
1.新建项目
2.引入依赖
3.application.properties
4.一键生成mybatis
5.新建工具类
6.实体类
7.controller文件
8.service层
三、前端vue实现交互
1.安装依赖
2.新建工具类
3.新建api类
4.新建页面
5.路由
四、最终结果
一、建立数据库
create databases db2024;
use db2024
DROP TABLE IF EXISTS `ucenter_member`;
CREATE TABLE `ucenter_member` (
`id` char(19) NOT NULL COMMENT '会员id',
`openid` varchar(128) DEFAULT NULL COMMENT '微信openid',
`mobile` varchar(11) DEFAULT '' COMMENT '手机号',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`nickname` varchar(50) DEFAULT NULL COMMENT '昵称',
`sex` tinyint(2) unsigned DEFAULT NULL COMMENT '性别 1 女,2 男',
`age` tinyint(3) unsigned DEFAULT NULL COMMENT '年龄',
`avatar` varchar(255) DEFAULT NULL COMMENT '用户头像',
`sign` varchar(100) DEFAULT NULL COMMENT '用户签名',
`is_disabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否禁用 1(true)已禁用, 0(false)未禁用',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除 1(true)已删除, 0(false)未删除',
`gmt_create` datetime NOT NULL COMMENT '创建时间',
`gmt_modified` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员表';
INSERT INTO `ucenter_member` VALUES ('1', null, '13700000001', '96e79218965eb72c92a549dd5a330112', '小三123', '1', '5', 'http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132', null, '0', '0', '2024-01-01 12:11:33', '2024-11-08 11:56:01');
通过上面的步骤就实现了数据库的建立和表的数据。
二、后端idea实现接口
1.新建项目
2.引入依赖
在pom.xml文件中把下面的代码赋值进去
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!-- 这里要是2.2.1,这样才能对应上tomcat-->
<version>2.2.1.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.xiyang.generator</groupId>
<artifactId>generator_method1</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 如果这里启动版本不对那么tomcat的版本也就和以前不一样了,不能是3.0以上,为2.0-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!--httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.2</version>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<!--swagger ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<!--日期时间工具-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
</dependency>
<!--tomcat10(包括10)之后需要的依赖-->
<!--jsp的依赖-->
<dependency>
<groupId>jakarta.servlet.jsp</groupId>
<artifactId>jakarta.servlet.jsp-api</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
<!--jar包的依赖-->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
<!--下面的依赖,是因为Java版本不对
解决Handler dispatch failed;nested exception is java.lang.NoClassDefFoundError:
javax/xml/bind/DatatypeConverter
-->
<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>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>
3.application.properties
在resources中建立文件
# 必须是这个端口
server.port=8160
spring.application.name=generator
# mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db2024?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
#mybatis
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#??mapper xml,这里看自己的路径是什么,别和我一模一样
mybatis-plus.mapper-locations=classpath:com/xiyang/generator/mapper/xml/*.xml
# 微信 appid
wx.open.app_id=wxed9954c01bb89b47
# 微信密钥 appsecret
wx.open.app_secret=a7482517235173ddb4083788de60b90e
# 微信 url
wx.open.redirect_url=http://localhost:8160/api/ucenter/wx/callback
4.一键生成mybatis
目录结构为,如果没有生成就看我的其他一篇博客:mybatis-generator之一键生成:两种方法-CSDN博客
5.新建工具类
①exception统一异常处理类,里面有两个文件GlobalExceptionHandler和XiyangException
package com.xiyang.generator.utils.exception;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
自定义异常处理
@Data
@AllArgsConstructor
@NoArgsConstructor
public class XiyangException extends RuntimeException{
private Integer code; //状态码
private String msg; //信息
}
package com.xiyang.generator.utils.exception;
import com.xiyang.generator.utils.R;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 统一异常处理类
*/
@ControllerAdvice
public class GlobalExceptionHandler {
// 出现全局异常就执行
@ExceptionHandler(Exception.class)
// 为了返回数据
@ResponseBody
public R error(Exception e) {
e.printStackTrace();
return R.error().message("执行全局异常处理");
}
// 特定异常处理---先找特殊异常处理然后再找全局异常处理
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public R error(ArithmeticException e){
e.printStackTrace();
return R.error().message("执行了ArithmeticException异常");
}
// 自定义异常处理--在编写代码的时候如果觉得这些代码可能会出现异常那么就要try catch
@ExceptionHandler(XiyangException.class)
@ResponseBody
public R error(XiyangException e){
e.printStackTrace();
return R.error().code(e.getCode()).message(e.getMsg());
}
}
②handler文件夹中有一个MyMetaObjectHandler,其作用就是实现数据库中时间代码的自动生成
package com.xiyang.generator.utils.handler;
//自动创建时间类
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
//自动填充
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// 属性名
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("gmtCreate",new Date(),metaObject);
this.setFieldValByName("gmtModified",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("gmtModified",new Date(),metaObject);
}
}
③ConstantPropertiesUtil用于读取application.properties中的属性
package com.xiyang.generator.utils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class ConstantPropertiesUtil implements InitializingBean {
@Value("${wx.open.app_id}")
private String appId;
@Value("${wx.open.app_secret}")
private String appSecret;
@Value("${wx.open.redirect_url}")
private String redirectUrl;
public static String WX_OPEN_APP_ID;
public static String WX_OPEN_APP_SECRET;
public static String WX_OPEN_REDIRECT_URL;
@Override
public void afterPropertiesSet() throws Exception {
WX_OPEN_APP_ID = appId;
WX_OPEN_APP_SECRET = appSecret;
WX_OPEN_REDIRECT_URL = redirectUrl;
}
}
④HttpClientUtils这里类用于实现微信扫描登录,这个是固定写法
package com.xiyang.generator.utils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 依赖的jar包有:commons-lang-2.6.jar、httpclient-4.3.2.jar、httpcore-4.3.1.jar、commons-io-2.4.jar
* @author zhaoyb
*
*/
public class HttpClientUtils {
public static final int connTimeout=10000;
public static final int readTimeout=10000;
public static final String charset="UTF-8";
private static HttpClient client = null;
static {
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(128);
cm.setDefaultMaxPerRoute(128);
client = HttpClients.custom().setConnectionManager(cm).build();
}
public static String postParameters(String url, String parameterStr) throws ConnectTimeoutException, SocketTimeoutException, Exception{
return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
}
public static String postParameters(String url, String parameterStr,String charset, Integer connTimeout, Integer readTimeout) throws ConnectTimeoutException, SocketTimeoutException, Exception{
return post(url,parameterStr,"application/x-www-form-urlencoded",charset,connTimeout,readTimeout);
}
public static String postParameters(String url, Map<String, String> params) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}
public static String postParameters(String url, Map<String, String> params, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
return postForm(url, params, null, connTimeout, readTimeout);
}
public static String get(String url) throws Exception {
return get(url, charset, null, null);
}
public static String get(String url, String charset) throws Exception {
return get(url, charset, connTimeout, readTimeout);
}
/**
* 发送一个 Post 请求, 使用指定的字符集编码.
*
* @param url
* @param body RequestBody
* @param mimeType 例如 application/xml "application/x-www-form-urlencoded" a=1&b=2&c=3
* @param charset 编码
* @param connTimeout 建立链接超时时间,毫秒.
* @param readTimeout 响应超时时间,毫秒.
* @return ResponseBody, 使用指定的字符集编码.
* @throws ConnectTimeoutException 建立链接超时异常
* @throws SocketTimeoutException 响应超时
* @throws Exception
*/
public static String post(String url, String body, String mimeType,String charset, Integer connTimeout, Integer readTimeout)
throws ConnectTimeoutException, SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
String result = "";
try {
if (StringUtils.isNotBlank(body)) {
HttpEntity entity = new StringEntity(body, ContentType.create(mimeType, charset));
post.setEntity(entity);
}
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(post);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null&& client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}
/**
* 提交form表单
*
* @param url
* @param params
* @param connTimeout
* @param readTimeout
* @return
* @throws ConnectTimeoutException
* @throws SocketTimeoutException
* @throws Exception
*/
public static String postForm(String url, Map<String, String> params, Map<String, String> headers, Integer connTimeout,Integer readTimeout) throws ConnectTimeoutException,
SocketTimeoutException, Exception {
HttpClient client = null;
HttpPost post = new HttpPost(url);
try {
if (params != null && !params.isEmpty()) {
List<NameValuePair> formParams = new ArrayList<NameValuePair>();
Set<Entry<String, String>> entrySet = params.entrySet();
for (Entry<String, String> entry : entrySet) {
formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formParams, Consts.UTF_8);
post.setEntity(entity);
}
if (headers != null && !headers.isEmpty()) {
for (Entry<String, String> entry : headers.entrySet()) {
post.addHeader(entry.getKey(), entry.getValue());
}
}
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
post.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(post);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(post);
}
return IOUtils.toString(res.getEntity().getContent(), "UTF-8");
} finally {
post.releaseConnection();
if (url.startsWith("https") && client != null
&& client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
}
/**
* 发送一个 GET 请求
*
* @param url
* @param charset
* @param connTimeout 建立链接超时时间,毫秒.
* @param readTimeout 响应超时时间,毫秒.
* @return
* @throws ConnectTimeoutException 建立链接超时
* @throws SocketTimeoutException 响应超时
* @throws Exception
*/
public static String get(String url, String charset, Integer connTimeout,Integer readTimeout)
throws ConnectTimeoutException,SocketTimeoutException, Exception {
HttpClient client = null;
HttpGet get = new HttpGet(url);
String result = "";
try {
// 设置参数
Builder customReqConf = RequestConfig.custom();
if (connTimeout != null) {
customReqConf.setConnectTimeout(connTimeout);
}
if (readTimeout != null) {
customReqConf.setSocketTimeout(readTimeout);
}
get.setConfig(customReqConf.build());
HttpResponse res = null;
if (url.startsWith("https")) {
// 执行 Https 请求.
client = createSSLInsecureClient();
res = client.execute(get);
} else {
// 执行 Http 请求.
client = HttpClientUtils.client;
res = client.execute(get);
}
result = IOUtils.toString(res.getEntity().getContent(), charset);
} finally {
get.releaseConnection();
if (url.startsWith("https") && client != null && client instanceof CloseableHttpClient) {
((CloseableHttpClient) client).close();
}
}
return result;
}
/**
* 从 response 里获取 charset
*
* @param ressponse
* @return
*/
@SuppressWarnings("unused")
private static String getCharsetFromResponse(HttpResponse ressponse) {
// Content-Type:text/html; charset=GBK
if (ressponse.getEntity() != null && ressponse.getEntity().getContentType() != null && ressponse.getEntity().getContentType().getValue() != null) {
String contentType = ressponse.getEntity().getContentType().getValue();
if (contentType.contains("charset=")) {
return contentType.substring(contentType.indexOf("charset=") + 8);
}
}
return null;
}
/**
* 创建 SSL连接
* @return
* @throws GeneralSecurityException
*/
private static CloseableHttpClient createSSLInsecureClient() throws GeneralSecurityException {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
public boolean isTrusted(X509Certificate[] chain,String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new X509HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
@Override
public void verify(String host, SSLSocket ssl)
throws IOException {
}
@Override
public void verify(String host, X509Certificate cert)
throws SSLException {
}
@Override
public void verify(String host, String[] cns,
String[] subjectAlts) throws SSLException {
}
});
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (GeneralSecurityException e) {
throw e;
}
}
public static void main(String[] args) {
try {
String str= post("https://localhost:443/ssl/test.shtml","name=12&page=34","application/x-www-form-urlencoded", "UTF-8", 10000, 10000);
//String str= get("https://localhost:443/ssl/test.shtml?name=12&page=34","GBK");
/*Map<String,String> map = new HashMap<String,String>();
map.put("name", "111");
map.put("page", "222");
String str= postForm("https://localhost:443/ssl/test.shtml",map,null, 10000, 10000);*/
System.out.println(str);
} catch (ConnectTimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SocketTimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
⑥JwtUtils这个类 属于是jwt生成token用的,安全机制,也是固定写法
package com.xiyang.generator.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
public class JwtUtils {
// 设置过期时间
public static final long EXPIRE = 1000 * 60 * 60 * 24;
// 设置密钥--这里随便什么都可以
public static final String APP_SECRET = "ukc8BDbRigUDaY6pZFfWus2jZWLPHO";
// 两个参数就是要放到jwt中的主体信息
public static String getJwtToken(String id, String nickname){
String JwtToken = Jwts.builder()
// 头信息的内容
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
// 设置过期时间
.setSubject("user")
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRE))
// 主体中的信息有id和nickname
.claim("id", id)
.claim("nickname", nickname)
// 使用加密算法等
.signWith(SignatureAlgorithm.HS256, APP_SECRET)
.compact();
// 生成一个token字符串
return JwtToken;
}
/**
* 下面的两个方法都是来判断token是否有效
* 判断token是否存在与有效
* @param jwtToken
* @return
**/
public static boolean checkToken(String jwtToken) {
// 没有就是false
if (StringUtils.isEmpty(jwtToken)) return false;
try {
// 不是有效也是false
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
* 这里的参数的request在headle中
* @param request
* @return
*/
public static boolean checkToken(HttpServletRequest request) {
try {
String jwtToken = request.getHeader("token");
if(StringUtils.isEmpty(jwtToken)) return false;
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 根据token字符串获取token字符串中的数据信息--这里只要得到id就行
* @param request
* @return
*/
public static String getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if (StringUtils.isEmpty(jwtToken)) return "";
// 得到用户信息
Jws<Claims> claimsJws =
Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(jwtToken);
// 得到主体
Claims claims = claimsJws.getBody();
return (String) claims.get("id");
}
}
⑦MD5,为了保护数据库中密码的安全,对密码的加密处理的处理方式就是MD5所以读取数据的时候要加密解密,就用这个固定类。
package com.xiyang.generator.utils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class MD5 {
public static String encrypt(String strSrc) {
try {
char hexChars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };
byte[] bytes = strSrc.getBytes();
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(bytes);
bytes = md.digest();
int j = bytes.length;
char[] chars = new char[j * 2];
int k = 0;
for (int i = 0; i < bytes.length; i++) {
byte b = bytes[i];
chars[k++] = hexChars[b >>> 4 & 0xf];
chars[k++] = hexChars[b & 0xf];
}
return new String(chars);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("MD5加密出错!!+" + e);
}
}
public static void main(String[] args) {
System.out.println(MD5.encrypt("111111"));
}
}
⑧R统一返回结果给前端
package com.xiyang.generator.utils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class R {
@ApiModelProperty(value = "是否成功")
private Boolean success;
@ApiModelProperty(value = "返回码")
private Integer code;
@ApiModelProperty(value = "返回消息")
private String message;
@ApiModelProperty(value = "返回数据")
private Map<String, Object> data = new HashMap<String, Object>();
private R(){}
public static R ok(){
R r = new R();
r.setSuccess(true);
r.setCode(ResultCode.SUCCESS);
r.setMessage("成功");
return r;
}
public static R error(){
R r = new R();
r.setSuccess(false);
r.setCode(ResultCode.ERROR);
r.setMessage("失败");
return r;
}
public R success(Boolean success){
this.setSuccess(success);
return this;
}
public R message(String message){
this.setMessage(message);
return this;
}
public R code(Integer code){
this.setCode(code);
return this;
}
public R data(String key, Object value){
this.data.put(key, value);
return this;
}
public R data(Map<String, Object> map){
this.setData(map);
return this;
}
}
⑨ResultCode状态码
package com.xiyang.generator.utils;
public interface ResultCode {
public static Integer SUCCESS = 20000;
public static Integer ERROR = 20001;
}
⑩swagger提示
package com.xiyang.generator.utils;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
//swagger配置类
@Configuration
@EnableSwagger2
public class swaggerConfig {
@Bean
public Docket webApiConfig() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("webApi")
.apiInfo(webApiInfo())
.select()
.paths(Predicates.not(PathSelectors.regex("/admin/.*")))
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build();
}
private ApiInfo webApiInfo(){
return new ApiInfoBuilder()
.title("登录-注册测试")
.description("本文档描述了登录注册接口定义")
.version("1.0")
.build();
}
}
6.实体类
为了方便登录注册的时候要的变量,所以新建两个类在entities中新建文件夹vo,里面创建两个类LoginVo和registerVo。
package com.xiyang.generator.entity.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value="登录对象", description="登录对象")
public class LoginVo {
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
}
package com.xiyang.generator.entity.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value="注册对象", description="注册对象")
public class RegisterVo {
@ApiModelProperty(value = "昵称")
private String nickname;
@ApiModelProperty(value = "手机号")
private String mobile;
@ApiModelProperty(value = "密码")
private String password;
@ApiModelProperty(value = "验证码")
private String code;
}
注意,一键生成的实体中对于主键要改为@TableId(value = "id", type = IdType.ID_WORKER_STR),对于生成的时间创建加上@TableField(fill = FieldFill.INSERT),而更新时间改为@TableField(fill = FieldFill.INSERT_UPDATE)。
7.controller文件
新建两个controller基本注册登录功能UcenterMemberController、微信扫描登录的WxApiController
package com.xiyang.generator.controller;
import com.xiyang.generator.entity.UcenterMember;
import com.xiyang.generator.entity.vo.LoginVo;
import com.xiyang.generator.entity.vo.RegisterVo;
import com.xiyang.generator.service.UcenterMemberService;
import com.xiyang.generator.utils.JwtUtils;
import com.xiyang.generator.utils.R;
import com.xiyang.generator.utils.exception.XiyangException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
/**
* <p>
* 会员表 前端控制器
* </p>
*
* @author xiyang
* @since 2024-05-09
*/
@RestController
@RequestMapping("/educenter/member")
@CrossOrigin
@Api(description = "登录与注册")
public class UcenterMemberController {
@Autowired
private UcenterMemberService ucenterMemberService;
@ApiOperation(value = "登录")
@PostMapping("login")
public R loginUser(@RequestBody LoginVo loginVo){
// 前端传递过来必须带有手机号和密码
// 登录的时候要返回token
String token = ucenterMemberService.login(loginVo);
return R.ok().data("token",token);
}
@ApiOperation(value = "注册")
@PostMapping("register")
public R registerUser(@RequestBody RegisterVo registerVo){
// 前端传递过来必须带有验证码、手机、昵称和密码
// 登录的时候要返回token
ucenterMemberService.register(registerVo);
return R.ok();
}
@ApiOperation(value = "根据token得到用户信息")
@GetMapping("getMemberInfo")
public R getMemberInfo(HttpServletRequest request){
try{
// 得到token
String memberId = JwtUtils.getMemberIdByJwtToken(request);
UcenterMember member = ucenterMemberService.getById(memberId);
return R.ok().data("memberInfo",member);
}catch (Exception e){
e.printStackTrace();
throw new XiyangException(20001,"获取用户信息失败");
}
}
}
package com.xiyang.generator.controller;
import com.google.gson.Gson;
import com.xiyang.generator.entity.UcenterMember;
import com.xiyang.generator.service.UcenterMemberService;
import com.xiyang.generator.utils.ConstantPropertiesUtil;
import com.xiyang.generator.utils.HttpClientUtils;
import com.xiyang.generator.utils.JwtUtils;
import com.xiyang.generator.utils.exception.XiyangException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
@CrossOrigin
@Controller //因为我们不要返回结果,所以这里是controller
//这里的路径必须是一样的
@RequestMapping("/api/ucenter/wx")
public class WxApiController {
@Autowired
private UcenterMemberService ucenterMemberService;
// 1.显示微信二维码
@GetMapping("login")
public String genWxCode(){
// 微信开放平台授权baseUrl--用于拼接url
String baseUrl = "https://open.weixin.qq.com/connect/qrconnect" +
"?appid=%s" +
"&redirect_uri=%s" +
"&response_type=code" +
"&scope=snsapi_login" +
"&state=%s" +
"#wechat_redirect";
// redirectUrl必须进行重新编码,防止错误格式
String redirectUrl = ConstantPropertiesUtil.WX_OPEN_REDIRECT_URL; //获取业务服务器重定向地址
try {
redirectUrl = URLEncoder.encode(redirectUrl, "UTF-8"); //url编码
} catch (UnsupportedEncodingException e) {
throw new XiyangException(20001, e.getMessage());
}
String qrcodeUrl = String.format(
baseUrl,
ConstantPropertiesUtil.WX_OPEN_APP_ID,
redirectUrl,
"xiyang");
return "redirect:" + qrcodeUrl;
}
// 2.微信扫码之后要跳转
// 必须是这样因为服务器就是这样写的,所以我们再重定向到本地的前端前台3000端口,有两个参数code和state
@GetMapping("callback")
public String callback(String code,String state){
try{
// 获取扫描人的信息然后把数据放到数据库中
// ①拿到code值请求微信固定的地址,得到两个值access_token和openid
String baseAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=%s" +
"&secret=%s" +
"&code=%s" +
"&grant_type=authorization_code";
// 拼接三个参数
String accessTokenUrl = String.format(
baseAccessTokenUrl,
ConstantPropertiesUtil.WX_OPEN_APP_ID,
ConstantPropertiesUtil.WX_OPEN_APP_SECRET,
code);
// 拼接地址之后,发送请求得到access_token和openid保存到accessTokenInfo
String accessTokenInfo = HttpClientUtils.get(accessTokenUrl);
// 但是只要里面的一部分,所以要把字符串只取部分并放到map中,使用gson工具
Gson gson = new Gson();
HashMap hashMap = gson.fromJson(accessTokenInfo, HashMap.class);
String accessToken = (String)hashMap.get("access_token");
String openid = (String)hashMap.get("openid");
// 把数据放到数据库中,但是重复的就不用加入,通过openid来判断
UcenterMember member = ucenterMemberService.getOpenIdMember(openid);
if(member == null){ //表中没有相同的微信数据,那么就加
// ②通过得到的这两个值,再使用固定的方法去请求固定的地址,得到扫描人的信息
// 访问微信的资源服务器,获取用户信息
String baseUserInfoUrl = "https://api.weixin.qq.com/sns/userinfo" +
"?access_token=%s" +
"&openid=%s";
String userInfoUrl = String.format(baseUserInfoUrl, accessToken, openid);
// 发送请求得到个人信息保存到userInfo
String userInfo = HttpClientUtils.get(userInfoUrl);
HashMap userInfoMap = gson.fromJson(userInfo, HashMap.class);
// 头像、昵称
String nickname = (String)userInfoMap.get("nickname");
String headimgurl = (String)userInfoMap.get("headimgurl");
member = new UcenterMember();
member.setOpenid(openid);
member.setNickname(nickname);
member.setAvatar(headimgurl);
// 添加到数据库中
ucenterMemberService.save(member);
}
// 使用jwt把扫描信息放到token中,并把token放到路径中传递给前端页面
String token = JwtUtils.getJwtToken(member.getId(), member.getNickname());
// 重定向,因为我的前端端口是3000,所以这里就固定了
return "redirect:http://localhost:3000?token="+token;
}catch (Exception e){
e.printStackTrace();
throw new XiyangException(20001,"扫描获取信息失败");
}
}
}
8.service层
UcenterMemberService文件
package com.xiyang.generator.service;
import com.xiyang.generator.entity.UcenterMember;
import com.baomidou.mybatisplus.extension.service.IService;
import com.xiyang.generator.entity.vo.LoginVo;
import com.xiyang.generator.entity.vo.RegisterVo;
/**
* <p>
* 会员表 服务类
* </p>
*
* @author xiyang
* @since 2024-05-09
*/
public interface UcenterMemberService extends IService<UcenterMember> {
String login(LoginVo loginVo);
void register(RegisterVo registerVo);
UcenterMember getOpenIdMember(String openid);
}
对应接口的实现UcenterMemberServiceImpl
package com.xiyang.generator.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xiyang.generator.entity.UcenterMember;
import com.xiyang.generator.entity.vo.LoginVo;
import com.xiyang.generator.entity.vo.RegisterVo;
import com.xiyang.generator.mapper.UcenterMemberMapper;
import com.xiyang.generator.service.UcenterMemberService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiyang.generator.utils.JwtUtils;
import com.xiyang.generator.utils.MD5;
import com.xiyang.generator.utils.exception.XiyangException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
/**
* <p>
* 会员表 服务实现类
* </p>
*
* @author xiyang
* @since 2024-05-09
*/
@Service
public class UcenterMemberServiceImpl extends ServiceImpl<UcenterMemberMapper, UcenterMember> implements UcenterMemberService {
// 因为验证码在数据库中,所以要把注入redis,但是我们没有实现短信验证
// @Autowired
// private RedisTemplate<String,String> redisTemplate;
@Override
public String login(LoginVo loginVo) {
String mobile = loginVo.getMobile();
String password = loginVo.getPassword();
if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)){
throw new XiyangException(20001,"手机号或密码为空");
}
// 按照手机号查询出一条记录
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
UcenterMember selectOne = baseMapper.selectOne(wrapper);
if(selectOne == null){
throw new XiyangException(20001,"该手机卡号未注册");
}
// 数据库中的密码是加密的,所以要把前端的密码进行加密再比较,使用工具类
if(!selectOne.getPassword().equals(MD5.encrypt(password))){
throw new XiyangException(20001,"密码错误");
}
if(selectOne.getIsDisabled()){
throw new XiyangException(20001,"该用户被禁用");
}
// 要生成token并返回给前端
String jwtToken = JwtUtils.getJwtToken(selectOne.getId(), selectOne.getNickname());
return jwtToken;
}
@Override
public void register(RegisterVo registerVo) {
String mobile = registerVo.getMobile();
String password = registerVo.getPassword();
String nickname = registerVo.getNickname();
String code = registerVo.getCode();
if(StringUtils.isEmpty(mobile) || StringUtils.isEmpty(password)
|| StringUtils.isEmpty(nickname) ||StringUtils.isEmpty(code)){
throw new XiyangException(20001,"有值为空");
}
// 先判断数据库中是否有这条手机数据,有的话就不能进行注册
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("mobile",mobile);
Integer count = baseMapper.selectCount(wrapper);
// count.intValue()个数大于一就不行
if(count.intValue() > 0){
throw new XiyangException(20001,"该手机号已被注册");
}
// 因为没有使用redis,否则这里应该是
// redisTemplate.opsForValue().get(mobile).equals(code);
if(!code.equals("9527")){
throw new XiyangException(20001,"验证码错误");
}
// 把数据放到数据库中
UcenterMember member = new UcenterMember();
member.setMobile(mobile);
member.setNickname(nickname);
member.setPassword(MD5.encrypt(password));
member.setIsDisabled(false); //用户是否被禁用
member.setAvatar("https://guli-file-190513.oss-cn-beijing.aliyuncs.com/avatar/default.jpg");
baseMapper.insert(member);
}
@Override
public UcenterMember getOpenIdMember(String openid) {
QueryWrapper<UcenterMember> wrapper = new QueryWrapper<>();
wrapper.eq("openid",openid);
UcenterMember member = baseMapper.selectOne(wrapper);
return member;
}
}
9.启动类
package com.xiyang.generator;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = {"com.xiyang"})
@MapperScan("com.xiyang.generator.mapper")
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class,args);
}
}
通过上面的所有步骤就实现了扫描登录、正常注册登录的过程。
三、前端vue实现交互
你已经建立起来了vue的基本框架,所以下面的代码就是在这个框架上生成的
1.安装依赖
npm stall js-cookie;npm install element-ui;npm install --save vue-router;npm install axios
2.新建工具类
新建方法request.js用于请求后端端口
import Axios from "axios";
// 引入cookie
import cookie from "js-cookie";
const service = Axios.create({
//后端地址
baseURL: "http://localhost:8160",
timeout: 20000
});
// 3.这里作为所有请端口的父端口,这里写拦截器
service.interceptors.request.use(
config => {
//debugger--cookie中没有token就把token放到cookie中
if (cookie.get("guli_token")) {
config.headers["token"] = cookie.get("guli_token");
}
return config;
},
err => {
return Promise.reject(err);
}
);
export default service;
3.新建api类
①login用于请求后端登录地址
import request from "@/utils/request"
// 登录相关接口
export default{
// 请求注册接口,传递json参数
loginUser(user){
return request({
url:`/educenter/member/login`,
method: 'post',
data: user
})
},
// getMemberInfo获取token中的头信息获取用户的信息
getMemberInfo(){
return request({
url:`/educenter/member/getMemberInfo`,
method: 'get',
})
}
}
②register用于请求后端注册接口
import request from "@/utils/request"
// 注册相关接口
export default{
// 请求注册接口,传递json参数
registerInfo(user){
return request({
url:`/educenter/member/register`,
method: 'post',
data: user
})
},
}
4.新建页面
①登录页面
<template>
<div class="main">
<div class="title">
<a class="active" href="/login">登录</a>
<span>·</span>
<a href="/register">注册</a>
</div>
<div class="sign-up-container">
<el-form ref="userForm" :model="user">
<el-form-item
class="input-prepend restyle"
prop="mobile"
:rules="[
{
required: true,
message: '请输入手机号码',
trigger: 'blur',
},
{ validator: checkPhone, trigger: 'blur' },
]"
>
<div>
<el-input type="text" placeholder="手机号" v-model="user.mobile" />
<i class="iconfont icon-phone" />
</div>
</el-form-item>
<el-form-item
class="input-prepend"
prop="password"
:rules="[{ required: true, message: '请输入密码', trigger: 'blur' }]"
>
<div>
<el-input
type="password"
placeholder="密码"
v-model="user.password"
/>
<i class="iconfont icon-password" />
</div>
</el-form-item>
<div class="btn">
<input
type="button"
class="sign-in-button"
value="登录"
@click="submitLogin()"
/>
</div>
</el-form>
<!-- 更多登录方式 -->
<div class="more-sign">
<h6>社交帐号登录</h6>
<ul>
<li>
<a
id="weixin"
class="weixin"
target="_blank"
href="http://localhost:8160/api/ucenter/wx/login"
>
<i class="iconfont icon-weixin" />
</a>
</li>
<li>
<a id="qq" class="qq" target="_blank" href="#">
<i class="iconfont icon-qq" />
</a>
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import "~/assets/css/sign.css";
import "~/assets/css/iconfont.css";
// 引入cookie
import cookie from 'js-cookie'
import loginApi from "../api/login";
export default {
layout: "sign",
data() {
return {
user: {
mobile: "",
password: "",
},
// 为了获取用户信息
loginInfo: {},
};
},
methods: {
// 1.登录
submitLogin() {
loginApi.loginUser(this.user).then((response) => {
if(response.data.success){
// 2.得到token并放到cookie中,参数表示cookie名称、cookie内容,作用范围
cookie.set("guli_token",response.data.data.token,{domain:"localhost"})
// 4.通过token得到数据并把数据放到cookie中
loginApi.getMemberInfo().then(response => {
this.loginInfo = response.data.data.memberInfo
cookie.set("guli_ucenter",JSON.stringify(this.loginInfo),{domain:"localhost"})
})
// 提示登录成功
this.$message({
type: "success",
message: "登录成功",
});
// 5.跳转路由
this.$router.push({ path: "/" });
}
});
},
checkPhone (rule, value, callback) {
//debugger
if (!(/^1[34578]\d{9}$/.test(value))) {
return callback(new Error('手机号码格式不正确'))
}
return callback()
}
},
};
</script>
<style>
.el-form-item__error {
z-index: 9999999;
}
</style>
②注册页面
<template>
<div class="main">
<div class="title">
<a href="/login">登录</a>
<span>·</span>
<a class="active" href="/register">注册</a>
</div>
<div class="sign-up-container">
<el-form ref="userForm" :model="params">
<el-form-item
class="input-prepend restyle"
prop="nickname"
:rules="[
{
required: true,
message: '请输入你的昵称',
trigger: 'blur'
}
]"
>
<div>
<el-input
type="text"
placeholder="你的昵称"
v-model="params.nickname"
/>
<i class="iconfont icon-user" />
</div>
</el-form-item>
<el-form-item
class="input-prepend restyle no-radius"
prop="mobile"
:rules="[
{ required: true, message: '请输入手机号码', trigger: 'blur' },
{
validator: checkPhone,
trigger: 'blur'
}
]"
>
<div>
<el-input
type="text"
placeholder="手机号"
v-model="params.mobile"
/>
<i class="iconfont icon-phone" />
</div>
</el-form-item>
<el-form-item
class="input-prepend restyle no-radius"
prop="code"
:rules="[
{ required: true, message: '请输入验证码', trigger: 'blur' }
]"
>
<div
style="width: 100%;display: block;float: left;position: relative"
>
<el-input type="text" placeholder="验证码" v-model="params.code" />
<i class="iconfont icon-phone" />
</div>
<div
class="btn"
style="position:absolute;right: 0;top: 6px;width:40%;"
>
<a
href="javascript:"
type="button"
@click="getCodeFun()"
:value="codeTest"
style="border: none;background-color: none"
>{{ codeTest }}</a
>
</div>
</el-form-item>
<el-form-item
class="input-prepend"
prop="password"
:rules="[
{
required: true,
message: '请输入密码',
trigger: 'blur'
}
]"
>
<div>
<el-input
type="password"
placeholder="设置密码"
v-model="params.password"
/>
<i class="iconfont icon-password" />
</div>
</el-form-item>
<div class="btn">
<input
type="button"
class="sign-up-button"
value="注册"
@click="submitRegister()"
/>
</div>
<p class="sign-up-msg">
点击 “注册” 即表示您同意并愿意遵守简书
<br />
<a target="_blank" href="http://www.jianshu.com/p/c44d171298ce">用户协议</a>
和
<a target="_blank" href="http://www.jianshu.com/p/2ov8x3">隐私政策</a>
。
</p>
</el-form>
<!-- 更多注册方式 -->
<div class="more-sign">
<h6>社交帐号直接注册</h6>
<ul>
<li>
<a
id="weixin"
class="weixin"
target="_blank"
href="http://localhost:8160/api/ucenter/wx/login"
><i class="iconfont icon-weixin"
/></a>
</li>
<li>
<a id="qq" class="qq" target="_blank" href="#"
><i class="iconfont icon-qq"
/></a>
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
import "~/assets/css/sign.css";
import "~/assets/css/iconfont.css";
import registerApi from "../api/register";
export default {
layout: "sign",
data() {
return {
params: {
mobile: "",
code: "",
nickname: "",
password: ""
},
sending: true, //是否发送验证码
second: 60, //倒计时间
codeTest: "获取验证码"
};
},
methods:{
// 获取验证码
getCodeFun(){
// 防止多次点击
if (!this.sending)
return
// 调用超时设计,并且不能再发送验证码
this.sending = false
this.timeDown()
},
// 超时设计
timeDown() {
let result = setInterval(() => {
--this.second;
// 把时间值给替换掉"获取验证码"
this.codeTest = this.second
if (this.second < 1) {
clearInterval(result);
// 超时完之后又能发送验证码
this.sending = true;
//this.disabled = false;
this.second = 60;
this.codeTest = "获取验证码"
}
}, 1000);
},
// 注册方法--也就是把数据放到数据库中
submitRegister(){
registerApi.registerInfo(this.params).then(response => {
//提示注册成功
this.$message({
type: 'success',
message: "注册成功"
})
// 跳转路由
this.$router.push({path: '/login'})
})
},
checkPhone (rule, value, callback) {
//debugger
if (!(/^1[34578]\d{9}$/.test(value))) {
return callback(new Error('手机号码格式不正确'))
}
return callback()
}
}
};
</script>
③首页
<template>
<div class="in-wrap">
<!-- 公共头引入 -->
<header id="header">
<section class="container">
<h1 id="logo">
<!-- <a href="#" title="谷粒学院">
<img src="~/assets/img/logo.png" width="100%" alt="谷粒学院" />
</a> -->
</h1>
<div class="h-r-nsl">
<ul class="nav">
<router-link to="/" tag="li" active-class="current" exact>
<a>首页</a>
</router-link>
</ul>
<!-- / nav -->
<!-- 当用户进行登录之后,这里就不能这样显示了 -->
<ul class="h-r-login">
<li v-if="!loginInfo.id" id="no-login">
<a href="/login" title="登录">
<em class="icon18 login-icon"> </em>
<span class="vam ml5">登录</span>
</a>
|
<a href="/register" title="注册">
<span class="vam ml5">注册</span>
</a>
</li>
<li v-if="loginInfo.id" id="is-login-one" class="mr10">
<a id="headerMsgCountId" href="#" title="消息">
<em class="icon18 news-icon"> </em>
</a>
<q class="red-point" style="display: none"> </q>
</li>
<li v-if="loginInfo.id" id="is-login-two" class="h-r-user">
<a href="/ucenter" title>
<img
:src="loginInfo.avatar"
width="30"
height="30"
class="vam picImg"
alt
/>
<span id="userName" class="vam disIb">
{{loginInfo.nickname}}
</span>
</a>
<a
href="javascript:void(0);"
title="退出"
@click="logout()"
class="ml5"
>退 出</a>
</li>
<!-- /未登录显示第1 li;登录后显示第2,3 li -->
</ul>
<aside class="h-r-search">
<form action="#" method="post">
<label class="h-r-s-box">
<input
type="text"
placeholder="输入你想学的课程"
name="queryCourse.courseName"
value
/>
<button type="submit" class="s-btn">
<em class="icon18"> </em>
</button>
</label>
</form>
</aside>
</div>
<aside class="mw-nav-btn">
<div class="mw-nav-icon"></div>
</aside>
<div class="clear"></div>
</section>
</header>
</div>
</template>
<script>
// 引入cookie
import cookie from "js-cookie";
import loginApi from "../api/login";
export default {
data() {
return {
token: "",
loginInfo: {
id: "",
age: "",
avatar: "",
mobile: "",
nickname: "",
sex: ""
}
};
},
created() {
// 获取微信扫描后端传递过来在路径上的token
this.token = this.$route.query.token
if(this.token){
this.wxLogin()
}else{
this.showInfo();
}
},
methods: {
wxLogin(){
// 先把token放到cookie中,然后再拦截,然后再请求信息
cookie.set("guli_token",this.token,{domain:"localhost"})
cookie.set("guli_ucenter",'',{domain:"localhost"})
loginApi.getMemberInfo().then(response => {
this.loginInfo = response.data.data.memberInfo
cookie.set("guli_ucenter",JSON.stringify(this.loginInfo),{domain:"localhost"})
})
},
// 显示用户信息
showInfo() {
// 得到的是字符串,要变为json
var userStr = cookie.get("guli_ucenter");
if (userStr) {
// 把字符串变为json
this.loginInfo = JSON.parse(userStr);
}
},
// 退出,清空cookie中值
logout(){
cookie.set("guli_token",'',{domain:"localhost"})
cookie.set("guli_ucenter",'',{domain:"localhost"})
this.$router.push({ path: "/" });
}
}
};
</script>
5.路由
路由自己看着来吧
import Vue from 'vue'
import Router from 'vue-router'
import App from './App.vue'
Vue.use(Router)
// 引入组件
import Home from './components/Home.vue';
import Login from './components/Login.vue';
import Register from './components/Register.vue';
// 创建Vue Router实例
const router = new VueRouter({
routes: [
{ path: '/', component: Home },
{ path: '/login', component: About },
{ path: '/register', component: Register },
],
});
// 创建和挂载根实例
new Vue({
router, // 使用router配置
render: h => h(App),
}).$mount('#app');