乐优商城:笔记(十一):用户微服务:LyUserApplication
文章目录
- 2.3.1 controller
- 2.3.2 service
- 2.3.3 服务端数据校验
- 什么是Hibernate Validator
- 给User添加校验
- 在User对象的部分属性上添加注解:
- 在controller上进行控制
1 创建用户中心
用户搜索到自己心仪的商品,接下来就要去购买,但是购买必须先登录。所以接下来我们编写用户中心,实现用户的登录和注册功能。因为用户中心的服务其它微服务也会调用,因此这里我们做聚合:
- ly-user:父工程,包含2个子工程: ly-user-interface:实体及接口
- ly-user-service:业务和服务
1.1 创建ly-user-interface
<?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"> <parent> <artifactId>ly-user</artifactId> <groupId>com.leyou.service</groupId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.leyou.service</groupId> <artifactId>ly-user-interface</artifactId> <dependencies> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-core</artifactId> <version>1.0.4</version> </dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency><dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.8.RELEASE</version> </dependency> </dependencies> </project>
1.2 创建ly-user-service
1.2.1 引入依赖
<?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"> <parent> <artifactId>ly-user</artifactId> <groupId>com.leyou.service</groupId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.leyou.service</groupId> <artifactId>ly-user-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- mybatis启动器 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!-- 通用Mapper启动器 --> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.leyou.service</groupId> <artifactId>ly-user-interface</artifactId> <version>${leyou.latest.version}</version> </dependency> <dependency> <groupId>com.leyou.common</groupId> <artifactId>ly-common</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </dependency> <dependency> <groupId>com.leyou.service</groupId> <artifactId>ly-auth-common</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency> </dependencies> </project>
1.2.2 配置文件
server: port: 8085 spring: application: name: user-service datasource: url: jdbc:mysql://localhost:3306/yun6 username: root password: 123 driver-class-name: com.mysql.jdbc.Driver rabbitmq: host: 192.168.124.128 username: leyou password: leyou virtual-host: /leyou redis: host: 192.168.124.128 eureka: client: service-url: defaultZone: http://127.0.0.1:10086/eureka instance: prefer-ip-address: true ip-address: 127.0.0.1 mybatis: type-aliases-package: com.leyou.user.pojo
1.2.3 启动类
@SpringBootApplication @EnableDiscoveryClient @MapperScan("com.leyou.user.mapper") public class LyUserService { public static void main(String[] args) { SpringApplication.run(LyUserService.class,args); } }
1.2.4 添加路由
2 后台功能实现
2.1 数据校验
2.1.1 实体类
@Table(name = "tb_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username;// 用户名 @JsonIgnore private String password;// 密码 private String phone;// 电话 private Date created;// 创建时间 @JsonIgnore private String salt;// 密码的盐值 }
注意:为了安全考虑。这里对password和salt添加了注解@JsonIgnore,这样在json序列化时,就不会把password和salt返回。
2.1.2 mapper
public interface UserMapper extends Mapper<User> { }
2.1.3 controller
功能说明
实现用户数据的校验,主要包括对:手机号、用户名的唯一性校验。
接口路径
GET /check/{data}/{type}
参数说明:
参数 | 说明 | 是否必须 | 数据类型 | 默认值 |
---|---|---|---|---|
data | 要校验的数据 | 是 | String | 无 |
type | 要校验的数据类型:1,用户名;2,手机; | 否 | Integer | 无 |
返回结果:
返回布尔类型结果:
- true:可用
- false:不可用
状态码:
- 200:校验成功
- 400:参数有误
- 500:服务器内部异常
@GetMapping("check/{data}/{type}") public ResponseEntity<Boolean> checkData( @PathVariable("data") String data, @PathVariable("type") Integer type){ return ResponseEntity.ok(userService.checkData(data, type)); }
2.1.4 service
//校验登录数据 public Boolean checkData(String data, Integer type) { User record = new User(); switch (type){ case 1: record.setUsername(data); break; case 2: record.setPhone(data); break; default: throw new LyException(ExceptionEnum.INVALID_USER_DATA_TYPE); } return userMapper.selectCount(record) == 0;//为0说明该手机号或者用户名可用,因为用户名或者手机号必须唯一 }
2.2 实现发送短信功能
短信微服务已经准备好,我们就可以继续编写用户中心接口了。
功能说明
根据用户输入的手机号,生成随机验证码,长度为6位,纯数字。并且调用短信服务,发送验证码到用户手机。
接口路径
POST /code
参数说明:
参数 | 说明 | 是否必须 | 数据类型 | 默认值 |
---|---|---|---|---|
phone | 用户的手机号码 | 是 | String | 无 |
返回结果:
无
状态码:
- 204:请求已接收
- 400:参数有误
- 500:服务器内部异常
2.2.1 controller
@PostMapping("code") public ResponseEntity<Void> sendCode(@RequestParam("phone") String phone){ userService.sendCode(phone); return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); }
2.2.2 service
这里的逻辑会稍微复杂:
- 生成随机验证码
- 将验证码保存到Redis中,用来在注册的时候验证
- 发送验证码到
ly-sms-service
服务,发送短信
// 发送短信验证码 public void sendCode(String phone) { // 生成key String key = KEY_PREFIX + phone; // 生成验证码 String code = NumberUtils.generateCode(6); Map<String, String> msg = new HashMap<>(); msg.put("phone", phone); msg.put("code", code); // 发送验证码 amqpTemplate.convertAndSend("ly.sms.exchange","sms.verify.code",msg); // 保存验证码到redis中 以供后续验证 redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES); }
注意:要设置短信验证码在Redis的缓存时间为5分钟
2.3 实现注册功能
功能说明
先对用户输入的短信验证码进行校验,随后实现用户注册功能,对用户密码进行加密存储,使用MD5加密,加密过程中使用随机码作为salt加盐。
接口路径
POST /register
参数说明:
form表单格式
参数 | 说明 | 是否必须 | 数据类型 | 默认值 |
---|---|---|---|---|
username | 用户名,格式为4~30位字母、数字、下划线 | 是 | String | 无 |
password | 用户密码,格式为4~30位字母、数字、下划线 | 是 | String | 无 |
phone | 手机号码 | 是 | String | 无 |
code | 短信验证码 | 是 | String | 无 |
返回结果:
无返回值。
状态码:
- 201:注册成功
- 400:参数有误,注册失败
- 500:服务器内部异常,注册失败
2.3.1 controller
@PostMapping("register") public ResponseEntity<Void> register(User user, @RequestParam("code") String code) { Boolean boo = this.userService.register(user, code); if (boo == null || !boo) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); } return new ResponseEntity<>(HttpStatus.CREATED); }
@RequestParam
:
get和post请求传的参数会自动转换赋值到@RequestParam
所注解的变量上
@RequestParam
(org.springframework.web.bind.annotation.RequestParam
)用于将指定的请求参数赋值给方法中的形参。
2.3.2 service
基本逻辑:
- 1)校验短信验证码
- 2)生成盐
- 3)对密码加密
- 4)写入数据库
// 用户注册 public void register(@Valid User user, String code) { // 校验验证码:redis中的验证码和页面的验证码进行比较 String cacheCode = redisTemplate.opsForValue().get(KEY_PREFIX + user.getPhone()); if(!StringUtils.equals(cacheCode, code)){ throw new LyException(ExceptionEnum.INVALID_VERIFY_CODE); } // 对密码进行加密 String salt = CodecUtils.generateSalt(); user.setSalt(salt); user.setPassword(CodecUtils.md5Hex(user.getPassword() , salt)); // 写入数据库 user.setCreated(new Date()); userMapper.insert(user); }
2.3.3 服务端数据校验
刚才虽然实现了注册,但是服务端并没有进行数据校验,而前端的校验是很容易被有心人绕过的。所以我们必须在后台添加数据校验功能:
我们这里会使用
Hibernate-Validator框架完成数据校验:
而SpringBoot的web启动器中已经集成了相关依赖:
什么是Hibernate Validator
Hibernate Validator是
Hibernate提供的一个开源框架,使用注解方式非常方便的实现服务端的数据校验。
hibernate Validator 是
Bean Validation的参考实现 。
Hibernate Validator提供了 JSR 303 规范中所有内置
constraint(约束) 的实现,除此之外还有一些附加的 constraint。
在日常开发中,
Hibernate Validator经常用来验证bean的字段,基于注解,方便快捷高效。
给User添加校验
我们在
ly-user-interface中添加
Hibernate-Validator依赖:
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency>
在User对象的部分属性上添加注解:
@Data @Table(name = "tb_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @NotEmpty(message = "用户名不能为空!") @Length(min = 4, max = 32, message = "用户名长度必须在4~32位之间") private String username;// 用户名 @Length(min = 4, max = 32, message = "密码长度必须在4~32位之间") @JsonIgnore private String password;// 密码 @Pattern(regexp = "^1([38][0-9]|4[579]|5[0-3,5-9]|6[6]|7[0135678]|9[89])\\d{8}$", message = "手机号码格式有误!") private String phone;// 电话 private Date created;// 创建时间 @JsonIgnore private String salt;// 密码的盐值 }
在controller上进行控制
要想校验生效,需要在controller上添加注解,
@Valid
如果输入的参数不符合规范,SpringMVC会自动返回错误信息。
可以看出所有错误信息的详细信息都被展示出来了,但是看着太繁琐了,我们想自己处理,怎么办呢?改造controller如下(这部分可以不做):
2.4 根据用户名和密码查询用户
功能说明
查询功能,根据参数中的用户名和密码查询指定用户
接口路径
GET /query
参数说明:
form表单格式
参数 | 说明 | 是否必须 | 数据类型 | 默认值 |
---|---|---|---|---|
username | 用户名,格式为4~30位字母、数字、下划线 | 是 | String | 无 |
password | 用户密码,格式为4~30位字母、数字、下划线 | 是 | String | 无 |
返回结果:
用户的json格式数据
{ "id": 6572312, "username":"test", "phone":"13688886666", "created": 1342432424 }
状态码:
- 200:注册成功
- 400:用户名或密码错误
- 500:服务器内部异常,注册失败
2.4.1 controller
@GetMapping("query") public ResponseEntity<User> queryUsernameAndPassword( @RequestParam("username") String username, @RequestParam("password") String password){ return ResponseEntity.ok(userService.queryUsernameAndPassword(username,password)); }
2.4.2 service
public User queryUsernameAndPassword(String username, String password) { User record = new User(); record.setUsername(username); // 根据用户名查询用户 User user = userMapper.selectOne(record); // 校验用户名 if(user == null){ throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD); } // 校验密码 if(! StringUtils.equals(user.getPassword(), CodecUtils.md5Hex(password , user.getSalt()))){ throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD); } return user; }
说明:我们查询的时候只根据用户名来查,因为我们在设计数据库时给用户名这个字段添加了索引,加了索引之后,极大提升了查询的效率,但是如果使用用户名和密码来查询,索引就变得形同虚设
做完了以上几步,在注册页点击注册,可以跳转到登录页,同时数据库中可以查询得到用户信息~
- 乐优商城:笔记(十五):订单微服务:LyOrderApplication
- 乐优商城--服务(七) : 用户中心微服务(LyUserApplication)
- 乐优商城--服务(四) : 上传微服务(LyUploadApplication)
- 乐优商城--服务(三) : 商品微服务(LyItemApplication)--前半部分
- 乐优商城--服务(三) : 商品微服务(LyItemApplication)--后半部分
- 乐优商城--服务(一): 注册微服务(LyRegister)
- 乐优商城:笔记(十二):鉴权微服务——授权
- 乐优商城:笔记(十三):鉴权微服务——鉴权
- windows无法连接到user profile service服务。此问题阻止标准用户登录系统
- 开机登录失败 提示"user profile service服务未能登录,无法加载用户配置文件" 问题解决办法
- Spring MVC 学习笔记5 —— 实现简单的用户管理,增删改查(1)建立user model
- (九)Java B2B2C o2o多用户商城-commonservice-config配置服务搭建
- Windows Server 笔记(六):Active Directory域服务:用户(1)
- Django商城项目笔记No.6用户部分-注册接口-短信验证码实现celery异步
- Linux自学笔记(十一)Linux之用户和用户组
- User Profile Service服务未能登录,无法加载用户配置
- User Profile Synchronization Service–Hangs on Starting (I fixed it!) 用户配置文件同步服务卡在“正在启动”状态
- Windows Server 笔记(六):Active Directory域服务:用户(4)
- 服务中读取当前用户注册表HKEY_CURRENT_USER
- user profile service服务未能登陆,无法加载用户配置文件