目录:
(1)前台用户系统-登录注册-需求分析
(2)前台用户系统-登录注册-搭建环境
(3)前台用户系统-手机登录-基本实现
(4)前台用户系统-手机登录-整合JWT
(1)前台用户系统-登录注册-需求分析
点击某一个科室,可以看到科室中号员的信息,排班信息,可以进行相关的挂号,在挂号之前需要进行登录,要知道谁去挂号,这个人的信息,最终进行相关的支付
在点击科室之前需要判断是否登录,没有登录,弹出登录框进行登录,点击有右上角的登录按钮,进行弹出框登录
- 登录效果
- 登录需求
- 登录采取弹出层的形式
- 登录方式:
- 手机号码+手机验证码
- 微信扫描
- 无注册界面,第一次登录根据手机号判断系统是否存在,如果不存在则自动注册
- 微信扫描登录成功必须绑定手机号码,即:第一次扫描成功后绑定手机号,以后登录扫描直接登录成功
- 网关统一判断登录状态(还可以用Session做判断),如何需要登录,页面弹出登录层
(2)前台用户系统-登录注册-搭建环境
在service-user模块中进行开发:首先先创建配置文件:
# 服务端口
server.port=8203
# 服务名
spring.application.name=service-user
# 环境设置:dev、test、prod
spring.profiles.active=dev
# mysql数据库连接
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/yygh_user?characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root123
#返回json的全局时间格式
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8
# nacos服务地址
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
#配置mapper xml文件的路径
mybatis-plus.mapper-locations=classpath:com/atguigu/yygh/user/mapper/xml/*.xml
创建启动类:
package com.atguigu.yygh.user;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = "com.atguigu")
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.atguigu")
public class ServiceUserApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceUserApplication.class, args);
}
}
配置网关:
在网关模块中添加:新的路由
实体类已经在model模块中引入了:
package com.atguigu.yygh.model.user;
import com.atguigu.yygh.model.base.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <p>
* UserInfo
* </p>
*
* @author qy
*/
@Data
@ApiModel(description = "UserInfo")
@TableName("user_info")
public class UserInfo extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "微信openid")
@TableField("openid")
private String openid;
@ApiModelProperty(value = "昵称")
@TableField("nick_name")
private String nickName;
@ApiModelProperty(value = "手机号")
@TableField("phone")
private String phone;
@ApiModelProperty(value = "用户姓名")
@TableField("name")
private String name;
@ApiModelProperty(value = "证件类型")
@TableField("certificates_type")
private String certificatesType;
@ApiModelProperty(value = "证件编号")
@TableField("certificates_no")
private String certificatesNo;
@ApiModelProperty(value = "证件路径")
@TableField("certificates_url")
private String certificatesUrl;
@ApiModelProperty(value = "认证状态(0:未认证 1:认证中 2:认证成功 -1:认证失败)")
@TableField("auth_status")
private Integer authStatus;
@ApiModelProperty(value = "状态(0:锁定 1:正常)")
@TableField("status")
private Integer status;
}
创建controller:UserInfoApiController
package com.atguigu.yygh.user.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/user")
public class UserInfoApiController {
}
创建service:UserInfoService
package com.atguigu.yygh.user.service;
public interface UserInfoService {
}
实现类:UserInfoService Impl:
package com.atguigu.yygh.user.service.impl;
import com.atguigu.yygh.model.user.UserInfo;
import com.atguigu.yygh.user.mapper.UserInfoMapper;
import com.atguigu.yygh.user.service.UserInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class UserInfoServiceImpl extends
ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
}
创建mapper:UserInfoMapper
package com.atguigu.yygh.user.mapper;
import com.atguigu.yygh.model.user.UserInfo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
UserInfoMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.atguigu.yygh.user.mapper.UserInfoMapper">
</mapper>
创建配置类:UserConfig :
package com.atguigu.yygh.user.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.atguigu.yygh.user.mapper")
public class UserConfig {
}
(3)前台用户系统-手机登录-基本实现
手机进行登录,登录的时候需要传入手机号和验证码,可以写一个vo类:
package com.atguigu.yygh.vo.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(description="登录对象")
public class LoginVo {
@ApiModelProperty(value = "openid")
private String openid;
@ApiModelProperty(value = "手机号")
private String phone;
@ApiModelProperty(value = "密码")
private String code;
@ApiModelProperty(value = "IP")
private String ip;
}
UserInfoApiController :
package com.atguigu.yygh.user.controller;
import com.atguigu.yygh.common.result.Result;
import com.atguigu.yygh.user.service.UserInfoService;
import com.atguigu.yygh.vo.user.LoginVo;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
@RequestMapping("/api/user")
public class UserInfoApiController {
@Autowired
private UserInfoService userInfoService;
//用户手机登录接口
@ApiOperation(value = "用户登录")
@PostMapping("login")
public Result login(@RequestBody LoginVo loginVo) {
Map<String, Object> info = userInfoService.login(loginVo);
return Result.ok(info);
}
}
UserInfoService:
package com.atguigu.yygh.user.service;
import com.atguigu.yygh.vo.user.LoginVo;
import java.util.Map;
public interface UserInfoService{
//用户手机登录接口
Map<String, Object> login(LoginVo loginVo);
}
实现类:UserInfoServiceImpl
package com.atguigu.yygh.user.service.impl;
import com.atguigu.yygh.common.exception.HospitalException;
import com.atguigu.yygh.common.result.ResultCodeEnum;
import com.atguigu.yygh.model.user.UserInfo;
import com.atguigu.yygh.user.mapper.UserInfoMapper;
import com.atguigu.yygh.user.service.UserInfoService;
import com.atguigu.yygh.vo.user.LoginVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserInfoServiceImpl extends
ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {
//用户手机登录接口
@Override
public Map<String, Object> login(LoginVo loginVo) {
//从loginVo里面获取输入的手机号和验证码
String phone = loginVo.getPhone();
String code = loginVo.getCode();
//校验参数 判断手机号和验证码是否为空
if(StringUtils.isEmpty(phone) || StringUtils.isEmpty(code)) {
throw new HospitalException(ResultCodeEnum.PARAM_ERROR);
}
//(整合阿里云短信服务)判断手机验证码和输入的验证码是否一致
//判断是否是第一次登录:根据手机号查询数据库,如果不存在相同的手机号就是第一次登录
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("phone", phone);
UserInfo userInfo = baseMapper.selectOne(queryWrapper);
if(null == userInfo) {//等于空表示第一次使用这个手机号登录
userInfo = new UserInfo();
userInfo.setName("");
userInfo.setPhone(phone);
userInfo.setStatus(1);
baseMapper.insert(userInfo);
}
//校验是否被禁用
if(userInfo.getStatus() == 0) {//判断用户状态是否为0禁用状态
throw new HospitalException(ResultCodeEnum.LOGIN_DISABLED_ERROR);
}
//不是第一次登录,直接登陆
//返回登录的信息 :返回用户名 返回tocken信息
Map<String, Object> map = new HashMap<>();
String name = userInfo.getName();
if(StringUtils.isEmpty(name)) {
name = userInfo.getNickName();
}
if(StringUtils.isEmpty(name)) {
name = userInfo.getPhone();
}
map.put("name", name);
map.put("token", "");
return map;
}
}
说明:
- 验证码先注释,后续校验
- 登录成功生成token,后续讲解
(4)前台用户系统-手机登录-整合JWT
JWT工具:tocken的生成,需要按照一定的规则,规则怎么样不确定,规则可以自己约定,在开发中呢,有一种通用的工具,叫做JWT,JWT给我们约定好了一种规则,用JWT帮助我们生成这样一段token的字符串,我们采用JWT的方式来生成token的字符串
JWT介绍
JWT工具
JWT(Json Web Token)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。
JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上
JWT最重要的作用就是对 token信息的防伪作用。由于自己定义的规则,用户可能猜到,进行伪造,JWT可以防伪:对某些字段进行加密、编码处理
JWT的原理,
一个JWT由三个部分组成:公共部分、私有部分、签名部分。最后由这三者组合进行base64编码得到JWT。
JWT:生成的tocken字符串由3部分组成:头部分,主体,签名哈希
把JWT放到common_util模块中:引入依赖
创建工具类:
package com.atguigu.yygh.common.helper;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;
import java.util.Date;
public class JwtHelper {
private static long tokenExpiration = 24*60*60*1000;//tonken的过期时间
private static String tokenSignKey = "123456";//token的签名秘钥 根据秘钥做一个编码,做一个签名,做一个加密
//根基参数生成token
public static String createToken(Long userId, String userName) {
String token = Jwts.builder()
.setSubject("YYGH-USER")
.setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))//过期时间
.claim("userId", userId) //主体信息
.claim("userName", userName) //主体信息
.signWith(SignatureAlgorithm.HS512, tokenSignKey)//签名哈希
.compressWith(CompressionCodecs.GZIP)
.compact();
return token;
}
//根据token字符串得到用户id
public static Long getUserId(String token) {
if(StringUtils.isEmpty(token)) return null;
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
Integer userId = (Integer)claims.get("userId");
return userId.longValue();
}
//根据token字符串得到用户名称
public static String getUserName(String token) {
if(StringUtils.isEmpty(token)) return "";
Jws<Claims> claimsJws
= Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return (String)claims.get("userName");
}
public static void main(String[] args) {
String token = JwtHelper.createToken(1L, "55");
System.out.println(token);
System.out.println(JwtHelper.getUserId(token));
System.out.println(JwtHelper.getUserName(token));
}
}
修改实现类上面没有写的token部分:UserInfoServiceImpl
使用swagger测试:
yygh_user数据库表user_info中的数据
点击:
数据库成功的加入一条信息: