代码地址
CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '昵称',
`userAccount` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '登录账号',
`avatarUrl` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '头像',
`gender` tinyint(1) NULL DEFAULT NULL COMMENT '性别',
`userPassword` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '密码',
`phone` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '电话',
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '邮箱',
`userStatus` int NOT NULL DEFAULT 0 COMMENT '用户状态:0正常',
`createTime` datetime NULL DEFAULT NULL COMMENT '创建时间,数据插入时间',
`updateTime` datetime NULL DEFAULT NULL COMMENT '更新时间,数据更新时间',
`isDelete` tinyint NOT NULL DEFAULT 0 COMMENT '是否删除:0未删除',
`role` int NOT NULL DEFAULT 0 COMMENT '0普通用户:1管理员',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.30version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.1version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>druidartifactId>
<version>1.1.16version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.33version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-lang3artifactId>
<version>3.12.0version>
dependency>
@Data
public class Result<T> implements Serializable {
private Integer code;
private String msg;
private T data;
public Result() {
}
public static Result ResultOk(Object data){
Result result = setCodeEnum(CodeEnum.SUCCESS);
if(data!=null) {
result.setData(data);
}
return result;
}
public static Result ResultOk(){
Result result = setCodeEnum(CodeEnum.SUCCESS);;
return result;
}
public static Result error(){
Result result = setCodeEnum(CodeEnum.ERROR);;
return result;
}
public static Result error(String msg){
Result result = setCodeEnum(CodeEnum.ERROR);
result.setMsg(msg);
return result;
}
public static Result setCodeEnum(CodeEnum enums){
Result result = new Result();
result.setCode(enums.getCode());
result.setMsg(enums.getMsg());
return result;
}
@Override
public String toString() {
return "Result{" +
"code=" + code +
", msg='" + msg + '\'' +
", data=" + data +
'}';
}
}
public enum CodeEnum {
// 成功
SUCCESS(200, "操作成功"),
// 失败
ERROR(400,"操作失败");
int code;
String msg;
CodeEnum(int code, String errorMessage) {
this.code = code;
this.msg = errorMessage;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
使用redis存放 邮箱验证码
@Configuration
public class RedisConfig {
@Bean
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
{
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
FastJsonRedisSerializer serializer = new FastJsonRedisSerializer(Object.class);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(serializer);
// Hash的key也采用StringRedisSerializer的序列化方式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
@Component
public class RedisCache
{
@Autowired
public RedisTemplate redisTemplate;
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value)
{
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
{
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout)
{
return expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
*
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit)
{
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获得缓存的基本对象。
*
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key)
{
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
*
* @param key
*/
public boolean deleteObject(final String key)
{
return redisTemplate.delete(key);
}
/**
* 删除集合对象
*
* @param collection 多个对象
* @return
*/
public long deleteObject(final Collection collection)
{
return redisTemplate.delete(collection);
}
/**
* 缓存List数据
*
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList)
{
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
}
/**
* 获得缓存的list对象
*
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheList(final String key)
{
return redisTemplate.opsForList().range(key, 0, -1);
}
/**
* 缓存Set
*
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
{
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
Iterator<T> it = dataSet.iterator();
while (it.hasNext())
{
setOperation.add(it.next());
}
return setOperation;
}
/**
* 获得缓存的set
*
* @param key
* @return
*/
public <T> Set<T> getCacheSet(final String key)
{
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
*
* @param key
* @param dataMap
*/
public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
{
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
*
* @param key
* @return
*/
public <T> Map<String, T> getCacheMap(final String key)
{
return redisTemplate.opsForHash().entries(key);
}
/**
* 往Hash中存入数据
*
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value)
{
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 获取Hash中的数据
*
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey)
{
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 删除Hash中的数据
*
* @param key
* @param hkey
*/
public void delCacheMapValue(final String key, final String hkey)
{
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.delete(key, hkey);
}
/**
* 获取多个Hash中的数据
*
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
{
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 获得缓存的基本对象列表
*
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern)
{
return redisTemplate.keys(pattern);
}
/**
* 更新redis文章浏览量
* @param key 哪一个哈希结构
* @param hKey 哈希表里哪一个数据
* @param v 更改值
*/
public void incrementCacheMapValue(String key,String hKey,long v){
redisTemplate.boundHashOps(key).increment(hKey, v);
}
}
/**
* Redis使用FastJson序列化
*/
public class FastJsonRedisSerializer<T> implements RedisSerializer<T>
{
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private Class<T> clazz;
static
{
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
}
public FastJsonRedisSerializer(Class<T> clazz)
{
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException
{
if (t == null)
{
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException
{
if (bytes == null || bytes.length <= 0)
{
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz);
}
protected JavaType getJavaType(Class<?> clazz)
{
return TypeFactory.defaultInstance().constructType(clazz);
}
}
新建domain
包,在domain
包中新建entity
包再在entity
中创建user实体类
/**
* (User)表实体类
* @author makejava
* @since 2023-04-28 14:23:28
*/
@SuppressWarnings("serial")
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User {
// 用户id@TableId
@TableId(value = "id" ,type = IdType.AUTO)
private Long id;
// 昵称
private String username;
// 登录账号
private String useraccount;
// 头像
private String avatarurl;
// 性别
private Integer gender;
// 密码
private String userpassword;
// 电话
private String phone;
// 邮箱
private String email;
// 用户状态:0正常
private Integer userstatus;
// 创建时间,数据插入时间
private Date createtime;
// 更新时间,数据更新时间
private Date updatetime;
// 是否删除:0未删除
private Integer isdelete;
// 0普通用户:1管理员
private Integer role;
}
新建mapper
包创建UserMapper
类
/**
* (User)表数据库访问层
*
* @author makejava
* @since 2023-04-28 14:23:25
*/
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
新建service
和其实现类
/**
* (User)表服务接口
*
* @author makejava
* @since 2023-04-28 14:23:32
*/
public interface UserService extends IService<User> {
}
/**
* (User)表服务实现类
*
* @author makejava
* @since 2023-04-28 14:23:33
*/
@Service()
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
新建controller
包新建UserController
类,定义用户注册的请求
@RestController // 适用于编写restful风格的api,返回值默认为json类型
@RequestMapping("/user")
public class UserController {
// 注册
}
@RestController // 适用于编写restful风格的api,返回值默认为json类型
@RequestMapping("/email")
public class EmailController {
// 发送验证码
}
server:
port: 8888
spring:
mail:
host: smtp.qq.com
protocol: smtp
default-encoding: UTF-8
username: [email protected]
password: *********** # 填上面生成的授权码
test-connection: true
properties:
mail:
smtp:
auth: true
starttls:
enable: true
required: true
port: 587
ToEmail
在domain
包下新建dto
包,在dto
包下创建ToEmail
package com.hzy.usercenter.domain.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @title: ToEmail
* @Author zxwyhzy
* @Date: 2023/4/28 14:47
* @Version 1.0
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ToEmail implements Serializable {
/**
* 邮件接收方
*/
private String to;
/**
* 邮件主题
*/
private String subject;
/**
* 邮件内容
*/
private String content;
}
EmailService
和其实现类public interface EmailService {
/**
* 发送验证码
* @param toEmail 邮箱数据传输类
* @return
*/
Result commonEmail(ToEmail toEmail);
}
@Service
public class EmailServiceImpl implements EmailService {
@Autowired
private JavaMailSender mailSender;
@Value("${spring.mail.username}")
private String from;
@Autowired
private UserService userService;
public Result commonEmail(ToEmail toEmail) {
// userService.isEmailNull(toEmail) 判断该邮箱是否已注册
if (userService.isEmailNull(toEmail)) {
//创建简单邮件消息
SimpleMailMessage message = new SimpleMailMessage();
//谁发的
message.setFrom(from);
//谁要接收
message.setTo(toEmail.getTo());
//邮件标题
message.setSubject(toEmail.getSubject());
//邮件内容
message.setText(toEmail.getContent());
try {
mailSender.send(message);
return Result.ResultOk(toEmail.getTo());
} catch (MailException e) {
e.printStackTrace();
return Result.error("发送失败");
}
}
return Result.error("该邮箱已注册");
}
}
实现isEmailNull()
public interface UserService extends IService<User> {
/**
* 判断邮箱是否注册
* @return true|false
*/
boolean isEmailNull(ToEmail toEmail);
}
@Override
public boolean isEmailNull(ToEmail toEmail) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getEmail,toEmail.getTo());
long count = count(queryWrapper);
if (count <1 )
return true;
return false;
}
@RestController
@RequestMapping("/mail")
public class EmailController {
@Autowired
private RedisCache redisCache;
@Autowired
EmailService emailService = new EmailServiceImpl();
@PostMapping
public Result SendMail(@RequestBody ToEmail toEmail){
toEmail.setSubject("注册验证码");
// RandomStringUtils commons-lang3引进的工具类
String yzm = RandomStringUtils.randomNumeric(6);
toEmail.setContent(yzm);
redisCache.setCacheObject(toEmail.getTo(),yzm);
// 验证码6分钟内有效
redisCache.expire(toEmail.getTo(),60*10);
return emailService.commonEmail(toEmail);
}
}
数据库添加邮箱为[email protected]的数据
/**
* 接收前端注册参数
* @title: UserRegisterRequest
* @Author zxwyhzy
* @Date: 2023/4/28 15:43
* @Version 1.0
*/
@Data
public class UserRegisterRequest {
// 用户名
private String userAccount;
// 密码
private String userPassword;
// 确认密码
private String checkPassword;
// 验证码
private String code;
// 邮箱
private String email;
}
@RestController // 适用于编写restful风格的api,返回值默认为json类型
@RequestMapping("/user")
public class UserController {
@Autowired
private RedisCache redisCache;
@Autowired
private UserService userService;
@PostMapping("/register")
public Result userRegister(@RequestBody UserRegisterRequest user){
if (null == user) return Result.error("参数不能为空");
String yzm = redisCache.getCacheObject(user.getEmail());
if (user.getCode()!=null && user.getCode().equals(yzm)){
return userService.userRegister(user);
}
return Result.error("验证码错误");
}
}
public interface UserService extends IService<User> {
/**
* 用户注册
* @param user 注册参数
* @return 是否注册功能 或失败原因
*/
Result userRegister(UserRegisterRequest user);
}
@Service()
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
private static final String SALT = "zy";
@Override
public Result userRegister(UserRegisterRequest user) {
// 虽然前端也会判断,但是有绕过前端直接发送请求的可能
if (StringUtils.isAnyBlank(user.getUserAccount(),
user.getUserPassword(),
user.getCheckPassword())){
return Result.error("用户名或密码为空");
}
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUseraccount,user.getUserAccount());
long count = count(queryWrapper);
if (count > 0 ) return Result.error("用户名以存在");
if (user.getUserPassword().equals(user.getCheckPassword())){
User register = new User();
register.setUseraccount(user.getUserAccount());
// 加密
String password = DigestUtils.md5DigestAsHex((SALT + user.getUserPassword()).getBytes());
register.setUserpassword(password);
boolean save = save(register);
if (!save){
return Result.error("注册失败");
}
return Result.ResultOk("注册成功");
}
return Result.error("两次输入的密码不一致");
}
}