【项目】【抽奖系统】注册功能实现
目录
- 一、用户注册
- 1.1 参数要求
- 1.2 接口规范
- 1.3 实现Controller
- 1.3.1 Validation
- 1.3.2 Controller实现
- 1.3.3 controller 的返回数据 UserRegisterResult
- 1.3.4 controller 的参数
- 1.3.5 添加的错误码
- 1.3.6 controller 层 全局异常捕获
- 1.3.7 测试
- 1.4 实现 service层
- 1.4.1 IUserService 接口
- 1.4.2 service层的返回结果 UserRegisterDTO
- 1.4.3 实现 service 接口
- 1.4.3.1 校验参数 checkRegisterInfo 方法
- 1.4.3.2 正则校验工具类 RegexUtil
- 1.4.3.3 身份枚举类 UserIdentityEnum
- 1.4.3.4 邮箱是否被使用 checkMailUsed 方法
- 1.4.3.5 手机号是否被使用 checkPhoneNumUsed 方法
- 1.4.4 添加的错误码
- 1.5 实现 dao
- 1.5.1 环境配置
- 1.5.2 UserMapperr 接口类
- 1.5.3 TypeHandler 自动运⾏处理功能
- 1.5.3.1 Encrypt 类 代表 phoneNumber
- 1.5.3.2 EncryptTypeHandler类:自己实现 TypeHandler
- 1.5.3.3 修改配置,使用自定义TypeHandle
- 1.5.4 测试
- 1.5.5 do层数据(相当于model)
- 1.6 前端

一、用户注册
时序图:
1.1 参数要求
参数名 | 描述 | 类型 | 默认值 | 条件 |
---|---|---|---|---|
name | 用户名 | String | 必须 | |
用户邮箱地址 | String | 必须 | ||
phoneNumber | 用户电话号码 | String | 必须 | |
password | 密码 | String | ||
identity | 管理员身份 | String | 必须 |
1.2 接口规范
[请求] /register POST
{"name":"张三","mail":"451@qq.com","phoneNumber":"13188888888","password":"123456789","identity":"ADMIN"
}
[响应]
{"code": 200,"data": {"userId": 22},"msg": ""
}
1.3 实现Controller
1.3.1 Validation
对于 controller 接⼝⼊参字段的验证,可以使⽤ Spring Boot 中集成的 Validation 来完成。例如可以看到我们在接⼝⼊参上加⼊了 @Validated 注解,并且 param 对象中的每个成员都使⽤@NotBlank 注解来检查参数不能为空。使⽤需引⼊依赖:
<!-- spring-boot 2.3及以上的版本只需要引⼊下⾯的依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>
1.3.2 Controller实现
com.yj.lottery_system.controller 包下实现
逻辑:
- @Validated 表示对参数进行校验 @RequestBody 接收JSON数据
- UserRegisterResult: Controller层的返回结果
- UserRegisterParam : Controller层的参数
- 调用service层服务
- convertToUserRegisterResult方法实现对service返回数据到Controller返回数据的转化
package com.yj.lottery_system.controller;import com.yj.lottery_system.common.errorcode.ControllerErrorCodeConstants;
import com.yj.lottery_system.common.exception.ControllerException;
import com.yj.lottery_system.common.pojo.CommonResult;
import com.yj.lottery_system.common.utils.JacksonUtil;
import com.yj.lottery_system.controller.param.UserRegisterParam;
import com.yj.lottery_system.controller.result.UserRegisterResult;
import com.yj.lottery_system.service.IUserService;
import com.yj.lottery_system.service.dto.UserRegisterDTO;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class UserController {private static final Logger log = LoggerFactory.getLogger(UserController.class);@Resourceprivate IUserService userService;/*** 注册*/@RequestMapping("/register")public CommonResult<UserRegisterResult> userRegister(@Validated @RequestBody UserRegisterParam param) {//日志打印log.info("userRegister UserRegisterParam: {}", JacksonUtil.writeValueAsString(param));//调用service服务UserRegisterDTO userRegisterDTO = userService.register(param);return CommonResult.success(convertToUserRegisterResult(userRegisterDTO));}private UserRegisterResult convertToUserRegisterResult(UserRegisterDTO userRegisterDTO) {UserRegisterResult userRegisterResult = new UserRegisterResult();if(null == userRegisterDTO) {throw new ControllerException((ControllerErrorCodeConstants.REGISTER_ERROR));}userRegisterResult.setUserId(userRegisterDTO.getUserId());return userRegisterResult;}
}
1.3.3 controller 的返回数据 UserRegisterResult
com.yj.lottery_system.controller.result 包下实现
根据接口规范,成功后的数据除码和信息外,只需要返回用户id。
package com.yj.lottery_system.controller.result;import lombok.Data;import java.io.Serializable;
@Data
public class UserRegisterResult implements Serializable {private Long userId;
}
1.3.4 controller 的参数
com.yj.lottery_system.controller.param 包下实现:
根据接口规范,参数包含 用户名,用户邮箱地址,用户电话,密码,身份标识。出 密码只有管理员有,不是必传参数外,其余都是必传参数, @NotBlank 注解校验String参数,禁止 null、空串、纯空格。
package com.yj.lottery_system.controller.param;import jakarta.validation.constraints.NotBlank;
import lombok.Data;import java.io.Serializable;@Data
public class UserRegisterParam implements Serializable {@NotBlank(message = "用户名不能为空")private String name;//用户名@NotBlank(message = "邮箱不能为空")private String mail;//用户邮箱地址@NotBlank(message = "电话不能为空")private String phoneNumber;//用户电话private String password;//密码,管理员才有@NotBlank(message = "身份标识不能为空")private String identity;//身份标识}
1.3.5 添加的错误码
com.yj.lottery_system.common.errorcode 包下ControllerErrorCodeConstants类中:
ErrorCode REGISTER_ERROR = new ErrorCode(100,"注册失败");
1.3.6 controller 层 全局异常捕获
控制层通⽤异常处理 @RestControllerAdvice+@ExceptionHandler
com.yj.lottery_system.controller.handler 包下实现:
- 捕获自定义的service层异常和controller层异常,还有没有捕获抛出的系统异常。
- 都打印日志,和返回错误码与堆栈信息。
package com.yj.lottery_system.controller.handler;import com.yj.lottery_system.common.errorcode.GlobalErrorCodeConstants;
import com.yj.lottery_system.common.exception.ControllerException;
import com.yj.lottery_system.common.exception.ServiceException;
import com.yj.lottery_system.common.pojo.CommonResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice //捕获全局抛的异常public class GlobalExceptionHandler {private final static Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);@ExceptionHandler(value = ServiceException.class)public CommonResult<?> serviceException(ServiceException e) {//错误日志LOGGER.error("ServiceException: ", e);//构造返回结果return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVICE_ERROR.getCode(), e.getMessage());}@ExceptionHandler(value = ControllerException.class)public CommonResult<?> controllerException(ControllerException e) {//错误日志LOGGER.error("ControllerException: ", e);//构造返回结果return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVICE_ERROR.getCode(), e.getMessage());}@ExceptionHandler(value = Exception.class)public CommonResult<?> exception(Exception e) {//错误日志LOGGER.error("ControllerException: ", e);//构造返回结果return CommonResult.error(GlobalErrorCodeConstants.INTERNAL_SERVICE_ERROR.getCode(), e.getMessage());}}
1.3.7 测试
我的service是实现了,只不过写在了后面。
正确传参:
- 传密码:
- 不传密码:
错误传参:
将后端写完后的正确测试:
1.4 实现 service层
1.4.1 IUserService 接口
com.yj.lottery_system.service 包下创建注册接口方法:
- UserRegisterParam :controller层传的参数。
- UserRegisterDTO :service层的返回结果。
package com.yj.lottery_system.service;import com.yj.lottery_system.controller.param.UserRegisterParam;
import com.yj.lottery_system.service.dto.UserRegisterDTO;public interface IUserService {/*** 注册*/UserRegisterDTO register(UserRegisterParam param);
}
1.4.2 service层的返回结果 UserRegisterDTO
com.yj.lottery_system.service.dto 下实现:
- controller层只需要service返回用户id。
package com.yj.lottery_system.service.dto;import lombok.Data;@Data
public class UserRegisterDTO {//用户idprivate Long userId;
}
1.4.3 实现 service 接口
com.yj.lottery_system.service.impl 包下:
package com.yj.lottery_system.service.impl;import ch.qos.logback.core.util.StringUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.yj.lottery_system.common.errorcode.ServiceErrorCodeConstants;
import com.yj.lottery_system.common.exception.ServiceException;
import com.yj.lottery_system.common.utils.RegexUtil;
import com.yj.lottery_system.controller.param.UserRegisterParam;
import com.yj.lottery_system.dao.dataObject.Encrypt;
import com.yj.lottery_system.dao.dataObject.UserDO;
import com.yj.lottery_system.dao.mapper.UserMapper;
import com.yj.lottery_system.service.IUserService;
import com.yj.lottery_system.service.dto.UserRegisterDTO;
import com.yj.lottery_system.service.enums.UserIdentityEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;@Service
public class UserServiceImpl implements IUserService {@Autowiredprivate UserMapper userMapper;@Overridepublic UserRegisterDTO register(UserRegisterParam param) {//校验参数checkRegisterInfo(param);//加密私密数据(构造dao层数据)UserDO userDO = new UserDO();userDO.setUserName(param.getName());userDO.setIdentity(param.getIdentity());userDO.setEmail(param.getMail());userDO.setPhoneNumber(new Encrypt(param.getPhoneNumber()));//有密码加密存储if(StringUtils.hasText(param.getPassword())) {userDO.setPassword(DigestUtil.sha256Hex(param.getPassword()));}//保存数据userMapper.insert(userDO);//构造返回UserRegisterDTO userRegisterDTO = new UserRegisterDTO();userRegisterDTO.setUserId(userDO.getId());return userRegisterDTO;}private void checkRegisterInfo(UserRegisterParam param) {//非空校验if(null == param) {throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);}//校验邮箱格式 xxx@xxx.xxx 正则表达式if(!RegexUtil.checkMail(param.getMail())) {throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);}//校验手机号格式if(!RegexUtil.checkMobile(param.getPhoneNumber())) {throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);}//校验身份信息if(null == UserIdentityEnum.forName(param.getIdentity())) {throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);}//校验管理员密码必填if(param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())&& !StringUtils.hasText(param.getPassword())) {throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_NULL);}//密码校验大于等于6位if(StringUtils.hasText(param.getPassword())&& !RegexUtil.checkPassword(param.getPassword())) {throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);}//校验邮箱是否被使用if(checkMailUsed(param.getMail())) {throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);}//校验手机号是否被使用if(checkPhoneNumUsed(param.getPhoneNumber())) {throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);}}//校验手机号是否被使用private boolean checkPhoneNumUsed(String phoneNumber) {int count = userMapper.countByPhone(new Encrypt(phoneNumber));return count > 0;}//校验邮箱是否被使用private boolean checkMailUsed(String mail) {//调用daoint count = userMapper.countByMail(mail);return count > 0;}
}
1.4.3.1 校验参数 checkRegisterInfo 方法
com.yj.lottery_system.service.impl 包下,UserServiceImpl 类中:
- 非空校验
- 调用正则校验工具类 RegexUtil 校验邮箱格式
- 调用正则校验工具类 RegexUtil 校验手机号格式
- 调用身份枚举类中的校验方法 UserIdentityEnum.forName 校验身份信息
- 校验管理员密码必填
- 调用正则校验工具类 RegexUtil 校验密码至少6位
- 调用checkMailUsed 校验邮箱是否被使用
- 调用 checkPhoneNumUsed 手机号是否被使用
private void checkRegisterInfo(UserRegisterParam param) {//非空校验if(null == param) {throw new ServiceException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);}//校验邮箱格式 xxx@xxx.xxx 正则表达式if(!RegexUtil.checkMail(param.getMail())) {throw new ServiceException(ServiceErrorCodeConstants.MAIL_ERROR);}//校验手机号格式if(!RegexUtil.checkMobile(param.getPhoneNumber())) {throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_ERROR);}//校验身份信息if(null == UserIdentityEnum.forName(param.getIdentity())) {throw new ServiceException(ServiceErrorCodeConstants.IDENTITY_ERROR);}//校验管理员密码必填if(param.getIdentity().equalsIgnoreCase(UserIdentityEnum.ADMIN.name())&& !StringUtils.hasText(param.getPassword())) {throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_IS_NULL);}//密码校验大于等于6位if(StringUtils.hasText(param.getPassword())&& !RegexUtil.checkPassword(param.getPassword())) {throw new ServiceException(ServiceErrorCodeConstants.PASSWORD_ERROR);}//校验邮箱是否被使用if(checkMailUsed(param.getMail())) {throw new ServiceException(ServiceErrorCodeConstants.MAIL_USED);}//校验手机号是否被使用if(checkPhoneNumUsed(param.getPhoneNumber())) {throw new ServiceException(ServiceErrorCodeConstants.PHONE_NUMBER_USED);}}
1.4.3.2 正则校验工具类 RegexUtil
com.yj.lottery_system.common.utils 包下:
package com.yj.lottery_system.common.utils;import org.springframework.util.StringUtils;import java.util.regex.Pattern;public class RegexUtil {/*** 邮箱:xxx@xx.xxx(形如:abc@qq.com)** @param content 邮箱* @return*/public static boolean checkMail(String content) {if (!StringUtils.hasText(content)) {return false;}/*** ^ 表⽰匹配字符串的开始。* [a-z0-9]+ 表⽰匹配⼀个或多个⼩写字⺟或数字。* ([._\\-]*[a-z0-9])* 表⽰匹配零次或多次下述模式:⼀个点、下划线、反斜杠或短横线,后⾯跟着⼀个或多个⼩写字⺟或数字。这部分是可选的,并且可以重复出现。* @ 字符字⾯量,表⽰电⼦邮件地址中必须包含的"@"符号。* ([a-z0-9]+[-a-z0-9]*[a-z0-9]+.) 表⽰匹配⼀个或多个⼩写字⺟或数字,后⾯可以跟着零个或多个短横线或⼩写字⺟和数字,然后是⼀个⼩写字⺟或数字,最后是⼀个点。这是匹配域名的⼀部分。* {1,63} 表⽰前⾯的模式重复1到63次,这是对顶级域名⻓度的限制。* [a-z0-9]+ 表⽰匹配⼀个或多个⼩写字⺟或数字,这是顶级域名的开始部分。* $ 表⽰匹配字符串的结束。*/String regex = "^[a-z0-9]+([._\\\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$";return Pattern.matches(regex, content);}/*** ⼿机号码以1开头的11位数字** @param content* @return*/public static boolean checkMobile(String content) {if (!StringUtils.hasText(content)) {return false;}/*** ^ 表⽰匹配字符串的开始。* 1 表⽰⼿机号码以数字1开头。* [3|4|5|6|7|8|9] 表⽰接下来的数字是3到9之间的任意⼀个数字。这是中国⼤陆⼿机号码的第⼆位数字,通常⽤来区分不同的运营商。* [0-9]{9} 表⽰后⾯跟着9个0到9之间的任意数字,这代表⼿机号码的剩余部分。* $ 表⽰匹配字符串的结束。*/String regex = "^1[3|4|5|6|7|8|9][0-9]{9}$";return Pattern.matches(regex, content);}/*** 密码强度正则,6到12位** @param content* @return*/public static boolean checkPassword(String content){if (!StringUtils.hasText(content)) {return false;}/*** ^ 表⽰匹配字符串的开始。* [0-9A-Za-z] 表⽰匹配的字符可以是:* 0-9:任意⼀个数字(0到9)。* A-Z:任意⼀个⼤写字⺟(从A到Z)。* a-z:任意⼀个⼩写字⺟(从a到z)。* {6,12} 表⽰前⾯的字符集合(数字、⼤写字⺟和⼩写字⺟)可以重复出现6到12次。* $ 表⽰匹配字符串的结束。*/String regex= "^[0-9A-Za-z]{6,12}$";return Pattern.matches(regex, content);}}
1.4.3.3 身份枚举类 UserIdentityEnum
com.yj.lottery_system.service.enums 包下:
- 只有管理员和普通用户两种身份
- 提供一个校验身份的静态方法
package com.yj.lottery_system.service.enums;import lombok.AllArgsConstructor;
import lombok.Getter;@Getter
@AllArgsConstructor
public enum UserIdentityEnum {ADMIN("管理员"),NORMAL("普通用户");private final String msg;public static UserIdentityEnum forName(String identity) {for(UserIdentityEnum userIdentityEnum : UserIdentityEnum.values()) {if(identity.equalsIgnoreCase( userIdentityEnum.name() )) {return userIdentityEnum;}}return null;}
}
1.4.3.4 邮箱是否被使用 checkMailUsed 方法
com.yj.lottery_system.service.impl 包,UserServiceImpl类:
调用dao层的方法即可
private boolean checkMailUsed(String mail) {//调用daoint count = userMapper.countByMail(mail);return count > 0;
}
1.4.3.5 手机号是否被使用 checkPhoneNumUsed 方法
com.yj.lottery_system.service.impl 包,UserServiceImpl类:
调用dao层的方法即可
//校验手机号是否被使用private boolean checkPhoneNumUsed(String phoneNumber) {int count = userMapper.countByPhone(new Encrypt(phoneNumber));return count > 0;}
1.4.4 添加的错误码
com.yj.lottery_system.common.errorcode 包下:
package com.yj.lottery_system.common.errorcode;public interface ServiceErrorCodeConstants {//人员模块错误码ErrorCode REGISTER_INFO_IS_EMPTY = new ErrorCode(100,"注册信息为空");ErrorCode MAIL_ERROR = new ErrorCode(101,"邮箱错误");ErrorCode PHONE_NUMBER_ERROR = new ErrorCode(102,"手机号错误");ErrorCode IDENTITY_ERROR = new ErrorCode(103,"身份错误");ErrorCode PASSWORD_IS_NULL = new ErrorCode(104,"管理员密码为空");ErrorCode PASSWORD_ERROR = new ErrorCode(105,"密码错误");ErrorCode MAIL_USED = new ErrorCode(106,"邮箱已被使用");ErrorCode PHONE_NUMBER_USED = new ErrorCode(107,"电话号已被使用");//活动模块错误码//奖品模块错误码//抽奖错误码
}
1.5 实现 dao
1.5.1 环境配置
pom.xml中添加Mybatis依赖和mysql驱动
<!-- Mybatis 依赖包 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency><!-- mysql驱动包 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency>
application.yml 添加配置项:
spring:application:name: lottery_systemdatasource:driver-class-name: com.mysql.cj.jdbc.Driver #MySql驱动类名称url: jdbc:mysql://127.0.0.1:3306/lottery_system?characterEncoding=utf8&useSSL=false #数据库连接的urlusername: rootpassword: 1234profiles:active: dev # 本地环境 部署后需要变成 spring.profiles.active=test## logback xml ##
logging:config: classpath:logback-spring.xml#服务器配置
server:port: 58081 #端口号## MyBatis ###配置mybatis xml的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件#这个项目使用的注解#mybatis.mapper-locations=classpath:mapper/*Mapper.xml#配置驼峰⾃动转换
mybatis:configuration:map-underscore-to-camel-case: true
1.5.2 UserMapperr 接口类
com.yj.lottery_system.dao.mapper 包下,UserMapper接口类:
- 我们使用注解的方式来调用数据库。
- 提供查询邮箱绑定人数的方法
- 提供新增 用户的方法,并且加上选项,将数据库自增 id 赋值给对象
package com.yj.lottery_system.dao.mapper;import com.yj.lottery_system.dao.dataObject.Encrypt;
import com.yj.lottery_system.dao.dataObject.UserDO;
import org.apache.ibatis.annotations.*;@Mapper
public interface UserMapper {/*** 查询邮箱绑定人数* @param email 邮箱* @return 绑定人数*/@Select("select count(*) from user where email = #{email}")int countByMail(@Param("email") String email);/*** 查询电话号绑定人数* @param phoneNumber 电话号码* @return 绑定人数*/@Select("select count(*) from user where phone_number = #{phoneNumber}")int countByPhone(@Param("phoneNumber") Encrypt phoneNumber);@Insert("insert into user (user_name, email, phone_number, password, identity)"+" values (#{userName},#{email},#{phoneNumber},#{password},#{identity})")@Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id")void insert(UserDO userDO);}
1.5.3 TypeHandler 自动运⾏处理功能
TypeHandler : 简单理解就是当处理某些特定字段时,我们可以实现⼀些⽅法,让 Mybatis 遇到这些特定字段可以⾃动运⾏处理。
1.5.3.1 Encrypt 类 代表 phoneNumber
因为 phoneNumber 是String类型,不可能使用 TypeHandler 时是将String类型全部处理,所以将 phoneNumber 单独使用一个类封装,处理这个类。
com.yj.lottery_system.dao.dataObject 包下:
package com.yj.lottery_system.dao.dataObject;import lombok.Data;@Data
public class Encrypt {private String value;public Encrypt() {}public Encrypt(String value) {this.value = value;}
}
1.5.3.2 EncryptTypeHandler类:自己实现 TypeHandler
com.yj.lottery_system.dao.handler 包下,EncryptTypeHandler类:
- 继承
BaseTypeHandler<T>
类型,T 传需要处理的类型 - 重写四个方法
- 在设置参数的时候进行加密
- 其余三个获取值的时候进行解密
package com.yj.lottery_system.dao.handler;import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.yj.lottery_system.dao.dataObject.Encrypt;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.springframework.util.StringUtils;import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;@MappedTypes(Encrypt.class) //被处理类型
@MappedJdbcTypes(JdbcType.VARCHAR) //转化后的jdbc类型
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> {//密钥private final byte[] KEY = "123456789abcdefg".getBytes(StandardCharsets.UTF_8);/**设置参数** @param ps SQL 预编译对象* @param i 需要赋值的索引位置* @param parameter 原本位置 i 需要赋的值* @param jdbcType jdbc类型* @throws SQLException*/@Overridepublic void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {if(null == parameter || null == parameter.getValue()) {ps.setString(i,null);return;}//加密AES aes = SecureUtil.aes(KEY);String s = aes.encryptHex(parameter.getValue());ps.setString(i,s);}/*** 获取值* @param rs 结果集* @param columnName 索引名* @return* @throws SQLException*/@Overridepublic Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException {return decrypt(rs.getString(columnName));}/*** 获取值* @param rs 结果集* @param columnIndex 索引位置* @return* @throws SQLException*/@Overridepublic Encrypt getNullableResult(ResultSet rs, int columnIndex) throws SQLException {return decrypt(rs.getString(columnIndex));}/*** 获取值* @param cs 结果集* @param columnIndex 索引位置* @return* @throws SQLException*/@Overridepublic Encrypt getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {return decrypt(cs.getString(columnIndex));}//解密 方法private Encrypt decrypt(String s) {if(!StringUtils.hasText(s)) {return null;}return new Encrypt(SecureUtil.aes(KEY).decryptStr(s));}
}
1.5.3.3 修改配置,使用自定义TypeHandle
application.yml中修改处理路径为自己的路径:
mybatis:type-handlers-package: com.yj.lottery_system.dao.handler #处理路径,替换成⾃⼰的
1.5.4 测试
1.5.5 do层数据(相当于model)
与数据库表中对应的类
每张表都有的id创建时间和更新时间,提取为公共类:
com.yj.lottery_system.dao.dataObject 包下 BaseDO 类:
package com.yj.lottery_system.dao.dataObject;import lombok.Data;import java.io.Serializable;
import java.util.Date;@Data
public class BaseDO implements Serializable {/*** 主键*/private Long id;/*** 创建时间*/private Date gmtCreate;/*** 修改时间*/private Date gmtModified;}
user表对应其他数据:
package com.yj.lottery_system.dao.dataObject;import lombok.Data;
import lombok.EqualsAndHashCode;@EqualsAndHashCode(callSuper = true)
@Data
public class UserDO extends BaseDO{/*** 邮箱*/private String email;/*** 身份信息*/private String identity;/*** 密码*/private String password;/*** 电话号码*/private Encrypt phoneNumber;/*** 用户名*/private String userName;
}
1.6 前端
register.html :
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>注册页面</title><link rel="stylesheet"href="https://cdn.staticfile.org/twitter-bootstrap/4.5.2/css/bootstrap.min.css"><link rel="stylesheet" href="./css/base.css"><scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script><scriptsrc="https://cdn.bootcdn.net/ajax/libs/jquery-validate/1.19.3/jquery.validate.min.js"></script><link rel="stylesheet"href="https://cdn.staticfile.org/twitter-bootstrap/4.5.2/js/bootstrap.min.js"><style>body {font-family: Arial, sans-serif;background-color: #fff;margin: 0;padding: 0;}.register-container {max-width: 600px;margin: 50px auto;padding: 20px;background-color: #fff;border-radius: 5px;}.register-container h2{font-weight: 600;font-size: 32px;letter-spacing: 1px;color: #000000;line-height: 50px;text-align: center;margin-bottom: 60px;}.show-password {float: right;cursor: pointer;color: #008CBA;}</style>
</head>
<body>
<div class="register-container"><h2>填写注册信息</h2><form id="registerForm"><div class="form-group"><label for="name">姓名</label><input type="text" class="form-control" id="name"name="name" placeholder="请输入姓名" required></div><div class="form-group"><label for="mail">邮箱</label><input type="email" class="form-control" id="mail"name="mail" placeholder="请输入邮箱" required></div><div class="form-group"><label for="phoneNumber">手机号</label><input type="text" class="form-control" id="phoneNumber"name="phoneNumber" placeholder="请输入手机号" required></div><div class="form-group"><label for="password">密码</label><input type="password" class="form-control" id="password"name="password" placeholder="请输入密码" required></div><button type="submit"class="btn btn-primary btn-block">注册</button></form>
</div><script>// 获取链接参数var params = new URLSearchParams(window.location.search);var jumpList = params.get('jumpList');var admin = params.get('admin');// 判断是否隐藏密码输入框if(admin === 'false') {// 隐藏密码输入框$('#password').closest('div.form-group').css('display', 'none');}// 使用jQuery Validate插件来验证表单$("#registerForm").validate({rules: {name: "required",mail: {required: true,email: true},phoneNumber: "required",password: {required: true,minlength: 6}},messages: {name: "请输入您的姓名",mail: "请输入有效的邮箱地址",phoneNumber: "请输入您的手机号",password: {required: "请输入密码",minlength: "密码长度至少为6个字符"}},submitHandler: function(form) {var formData = {name: $('#name').val(),mail: $('#mail').val(),phoneNumber: $('#phoneNumber').val(),password: $('#password').val(),identity: (admin == null || admin === 'true') ? "ADMIN" : "NORMAL"};// 表单验证通过后,发送AJAX请求$.ajax({url: '/register',type: 'POST',contentType: 'application/json',data: JSON.stringify(formData),success: function(result) {if (result.code != 200) {alert("注册失败!" + result.msg);} else {if (jumpList === 'true') {// 给父页面发消息,表示要跳转到人员列表页window.parent.postMessage({from: 'user-list.html',id: '#userList'}, '*');} else {alert("注册成功,去登录!");location.assign("blogin.html");}}}});return false; // 阻止表单的默认提交行为}});
</script>
</body>
</html>