redis相应配置

This commit is contained in:
YuNan 2024-11-09 16:49:13 +08:00
parent 116a304c02
commit be99853779
15 changed files with 1506 additions and 536 deletions

View File

@ -3,12 +3,17 @@ package com.yunan;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@Slf4j @Slf4j
@SpringBootApplication(scanBasePackages = "com.yunan") @SpringBootApplication(scanBasePackages = "com.yunan")
@EnableCaching//开启缓存
@EnableScheduling // 启用定时任务
public class YuNanDemoApplication { public class YuNanDemoApplication {
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -1,30 +1,147 @@
package com.yunan.config; package com.yunan.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
/*告诉spring,运行的时候加载读取这个类*/ /*告诉spring,运行的时候加载读取这个类*/
@Slf4j @Slf4j
@Configuration @Configuration
public class RedisConfig { public class RedisConfig {
@Bean @Bean
public RedisTemplate<String, Object> @SuppressWarnings("all")
redisTemplate(RedisConnectionFactory connectionFactory) { public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new //为了使开发方便直接使用<String, Object>
RedisTemplate<String, Object>(); RedisTemplate<String, Object> template = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer()); template.setConnectionFactory(factory);
redisTemplate.setValueSerializer //Json序列化配置
(new JdkSerializationRedisSerializer()); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
redisTemplate.setConnectionFactory(connectionFactory); ObjectMapper objectMapper = new ObjectMapper();
log.info("redis配置已加载"); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
return redisTemplate; objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//string的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用string的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash的key也是用string的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
//hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
// 输出 Redis 配置信息
log.info("Redis配置已加载");
// 检查 Redis 客户端类型并获取配置
if (factory instanceof LettuceConnectionFactory) {
LettuceConnectionFactory lettuceConnectionFactory = (LettuceConnectionFactory) factory;
String redisHost = lettuceConnectionFactory.getHostName();
int redisPort = lettuceConnectionFactory.getPort();
// log.info("Redis 连接地址: \t http://"+ redisHost + ":" + redisPort);
log.info("Redis 连接地址: {}:{}", redisHost , redisPort);
} else if (factory instanceof RedisStandaloneConfiguration) {
RedisStandaloneConfiguration config = (RedisStandaloneConfiguration) factory;
String redisHost = config.getHostName();
int redisPort = config.getPort();
log.info("Redis 连接地址: \t http://"+ redisHost +":"+ redisPort);
} }
return template;
}
/**
* 实例化具体的缓存配置!
* 设置缓存方式JSON
* 设置缓存时间 单位秒
* @param ttl
* @return
*/
private RedisCacheConfiguration redisCacheConfiguration(Long ttl){
//设置jackson序列化工具
Jackson2JsonRedisSerializer<Object> objectJackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
//常见jackson的对象映射器,并设置一些基本属性
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(MapperFeature.USE_ANNOTATIONS,false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.activateDefaultTyping(
LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY);
objectJackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(ttl))//设置缓存时间
.disableCachingNullValues()
.serializeKeysWith(keyPair())
.serializeValuesWith(valuePair());
}
//配置缓存管理器
@Bean("cacheManagerHour")
@Primary //同类型,多个bean,默认生效! 默认缓存时间1小时! 可以选择!
public CacheManager cacheManagerHour(RedisConnectionFactory factory){
//缓存时间一小时
RedisCacheConfiguration redisCacheConfiguration = redisCacheConfiguration( 3600L);
//构建缓存对象
return RedisCacheManager.builder(factory)
.cacheDefaults(redisCacheConfiguration)
.transactionAware()
.build();
}
//缓存一天的配置
@Bean(name ="cacheManagerDay")
public RedisCacheManager cacheManagerDay(RedisConnectionFactory factory){
//缓存时间为一天
RedisCacheConfiguration redisCacheConfiguration = redisCacheConfiguration(24 * 3600L);
return RedisCacheManager.builder(factory)
.cacheDefaults(redisCacheConfiguration)
.transactionAware()
.build();
}
/**
* 配置键序列化
* @return String序列化
*/
@Bean
RedisSerializationContext.SerializationPair<String> keyPair(){
return RedisSerializationContext.SerializationPair.fromSerializer( new StringRedisSerializer());
}
/**
* 配置值序列化
* @return GenericJackson2JsonRedisSerializer序列化Object
*/
@Bean
RedisSerializationContext.SerializationPair<Object> valuePair(){
return RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer());
}
} }

View File

@ -53,9 +53,7 @@ public class AuthController {
@PostMapping("/register") @PostMapping("/register")
@ApiOperation("用户注册") @ApiOperation("用户注册")
public ResponseEntity<Object> register(@RequestBody @Valid RegisterDTO registerDTO) throws MessagingException, UnsupportedEncodingException { public ResponseEntity<Object> register(@RequestBody @Valid RegisterDTO registerDTO) throws MessagingException, UnsupportedEncodingException {
//获取发送的验证码 return authService.register(registerDTO);
String rightCode = emailCodeMap.get(registerDTO.getEmail());
return authService.register(registerDTO, rightCode);
} }
// 存储已发送的验证码 // 存储已发送的验证码
@ -70,19 +68,9 @@ public class AuthController {
@PostMapping("/sendEmail") @PostMapping("/sendEmail")
@ApiOperation("邮箱验证码") @ApiOperation("邮箱验证码")
public ApiResponse<String> sendEmail(@RequestBody @Valid RegisterDTO registerDTO) throws MessagingException { public ApiResponse<String> sendEmail(@RequestBody @Valid RegisterDTO registerDTO) throws MessagingException {
// 生成验证码
String code = VerificationCodeUtils.generateCode(6);
// 发送邮件 return emailService.sendMail(registerDTO.getEmail());
String subject = "注册验证码";
String content = "尊敬的用户,您的验证码为:" + code;
emailService.sendMail(registerDTO.getEmail(), subject, content);
// 保存验证码
emailCodeMap.put(registerDTO.getEmail(), code);
return new ApiResponse<>(ResponseCode.SUCCESS,"验证码已发送");
} }

View File

@ -1,7 +1,7 @@
package com.yunan.controller; package com.yunan.controller;
import com.yunan.dto.Captcha; import com.yunan.dto.Captcha;
import com.yunan.response.R; import com.yunan.response.Result;
import com.yunan.service.CaptchaService; import com.yunan.service.CaptchaService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
@ -24,8 +24,8 @@ public class CaptchaController {
@ApiOperation(value = "生成验证码拼图") @ApiOperation(value = "生成验证码拼图")
@PostMapping("get-captcha") @PostMapping("get-captcha")
public R getCaptcha(@RequestBody Captcha captcha) { public Result getCaptcha(@RequestBody Captcha captcha) {
return R.ok(captchaService.getCaptcha(captcha)); return Result.ok(captchaService.getCaptcha(captcha));
} }
} }

View File

@ -5,7 +5,7 @@ import java.io.Serializable;
/** /**
* 用户实体类 * 用户实体类
*/ */
public class User implements Serializable { public class Users implements Serializable {
private Integer id; private Integer id;
/** 用户名*/ /** 用户名*/
private String username; private String username;
@ -14,20 +14,20 @@ public class User implements Serializable {
/** 邮箱*/ /** 邮箱*/
private String email; private String email;
/** 创建用户信息时间 */ /** 创建用户信息时间 */
private String createTime; private String createdTime;
/** 修改用户信息时间 */ /** 修改用户信息时间 */
private String updateTime; private String updatedTime;
/** 用户状态*/ /** 用户状态*/
private int state; private int state;
@Override @Override
public String toString() { public String toString() {
return "User{" + return "Users{" +
"username='" + username + '\'' + "username='" + username + '\'' +
", password='" + password + '\'' + ", password='" + password + '\'' +
", email='" + email + '\'' + ", email='" + email + '\'' +
", createTime='" + createTime + '\'' + ", createTime='" + createdTime + '\'' +
", updateTime='" + updateTime + '\'' + ", updateTime='" + updatedTime + '\'' +
", state=" + state + ", state=" + state +
'}'; '}';
} }
@ -56,11 +56,11 @@ public class User implements Serializable {
this.password = password; this.password = password;
} }
public String getEmai() { public String getEmail() {
return email; return email;
} }
public void setEmai(String email) { public void setEmail(String email) {
this.email = email; this.email = email;
} }
@ -72,19 +72,19 @@ public class User implements Serializable {
this.state = state; this.state = state;
} }
public String getCreate_Time() { public String getCreated_Time() {
return createTime; return createdTime;
} }
public void setCreate_Time(String create_Time) { public void setCreated_Time(String create_Time) {
this.createTime = create_Time; this.createdTime = create_Time;
} }
public String getUpdate_Time() { public String getUpdated_Time() {
return updateTime; return updatedTime;
} }
public void setUpdate_Time(String update_Time) { public void setUpdated_Time(String update_Time) {
this.updateTime = update_Time; this.updatedTime = update_Time;
} }
} }

View File

@ -1,10 +1,10 @@
package com.yunan.mapper; package com.yunan.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yunan.dto.User; import com.yunan.dto.Users;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
@Mapper @Mapper
public interface AuthMapper extends BaseMapper<User> { public interface AuthMapper extends BaseMapper<Users> {
} }

View File

@ -1,35 +1,34 @@
package com.yunan.response; package com.yunan.response;
public class R { public class Result {
private int code; // 状态码200代表成功其他代表失败 private int code; // 状态码200代表成功其他代表失败
private String message; // 响应信息 private String message; // 响应信息
private Object data; // 响应数据 private Object data; // 响应数据
// 默认构造函数 // 默认构造函数
public R() { public Result() {
} }
// 构造函数 // 构造函数
public R(int code, String message, Object data) { public Result(int code, String message, Object data) {
this.code = code; this.code = code;
this.message = message; this.message = message;
this.data = data; this.data = data;
} }
// 成功返回 // 成功返回
public static R ok(Object data) { public static Result ok(Object data) {
return new R(200, "成功", data); // 200代表成功 return new Result(200, "成功", data); // 200代表成功
} }
// 错误返回 // 错误返回
public static R error(String message) { public static Result error(String message) {
return new R(500, message, null); // 500代表服务器错误message为错误信息 return new Result(500, message, null); // 500代表服务器错误message为错误信息
} }
// 错误返回带code和message // 错误返回带code和message
public static R error(int code, String message) { public static Result error(int code, String message) {
return new R(code, message, null); // 根据传入的code返回不同的错误 return new Result(code, message, null); // 根据传入的code返回不同的错误
} }
// get set 方法 // get set 方法
@ -60,11 +59,10 @@ public class R {
// 重写toString方法方便调试输出 // 重写toString方法方便调试输出
@Override @Override
public String toString() { public String toString() {
return "R{" + return "Result{" +
"code=" + code + "code=" + code +
", message='" + message + '\'' + ", message='" + message + '\'' +
", data=" + data + ", data=" + data +
'}'; '}';
} }
} }

View File

@ -10,5 +10,5 @@ import java.io.UnsupportedEncodingException;
public interface AuthService { public interface AuthService {
ResponseEntity<Object> register(RegisterDTO registerDTO, String rightCode) throws UnsupportedEncodingException, AddressException, MessagingException; ResponseEntity<Object> register(RegisterDTO registerDTO) throws UnsupportedEncodingException, AddressException, MessagingException;
} }

View File

@ -1,6 +1,7 @@
package com.yunan.service; package com.yunan.service;
import com.yunan.response.ApiResponse;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.mail.MessagingException; import javax.mail.MessagingException;
@ -8,7 +9,7 @@ import javax.mail.MessagingException;
@Service @Service
public interface EmailService { public interface EmailService {
void sendMail(String email, String subject, String content) throws MessagingException; ApiResponse<String> sendMail(String email) throws MessagingException;
} }

View File

@ -0,0 +1,43 @@
package com.yunan.service;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import java.util.Set;
import java.util.stream.Collectors;
@Service
public class RedisExpireTask {
private final long time = 300000; //五分钟
private RedisTemplate<String, Object> redisTemplate;
public RedisExpireTask(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
// 每隔一分钟执行一次
@Scheduled(fixedRate = time)
public void removeExpiredKeys() {
long now = System.currentTimeMillis();
// 获取过期的 hashKey
Set<Object> expiredHashKeys = redisTemplate.opsForZSet().rangeByScore("rightCode:expire", 0, now);
if (expiredHashKeys != null && !expiredHashKeys.isEmpty()) {
// Set<Object> 转换为 Set<String>
Set<String> expiredHashKeysSet = expiredHashKeys.stream()
.map(Object::toString) // Object 转换为 String
.collect(Collectors.toSet());
// 删除过期的数据
redisTemplate.opsForZSet().remove("rightCode:expire", expiredHashKeysSet.toArray(new String[0]));
// 同时从哈希表中删除对应的 hashKey
for (String hashKey : expiredHashKeysSet) {
redisTemplate.opsForHash().delete("rightCode", hashKey);
}
}
}
}

View File

@ -2,10 +2,12 @@ package com.yunan.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yunan.dto.RegisterDTO; import com.yunan.dto.RegisterDTO;
import com.yunan.dto.Users;
import com.yunan.mapper.AuthMapper; import com.yunan.mapper.AuthMapper;
import com.yunan.dto.User;
import com.yunan.response.ErrorResponse; import com.yunan.response.ErrorResponse;
import com.yunan.service.AuthService; import com.yunan.service.AuthService;
import com.yunan.util.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -18,25 +20,30 @@ import javax.annotation.Resource;
public class AuthServiceImpl implements AuthService { public class AuthServiceImpl implements AuthService {
@Resource @Resource
private AuthMapper authMapper; private AuthMapper authMapper;
@Autowired
RedisUtils redisUtils;
@Override @Override
public ResponseEntity<Object> register(RegisterDTO registerDTO, String rightCode) { public ResponseEntity<Object> register(RegisterDTO registerDTO) {
//获取正确的验证码
Object rightCode = redisUtils.hGet("rightCode", registerDTO.getEmail());
//处理registerDTO对数据为空的逻辑 //处理registerDTO对数据为空的逻辑
// 验证验证码的正确性 // 验证验证码的正确性
if(registerDTO.getCode() == rightCode){ if(registerDTO.getCode().equals(rightCode)){
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Users> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUsername, registerDTO.getUsername()); queryWrapper.eq(Users::getEmail, registerDTO.getEmail());
if(authMapper.selectOne(queryWrapper) != null) { if(authMapper.selectOne(queryWrapper) != null) {
return ResponseEntity return ResponseEntity
.status(HttpStatus.CONFLICT) .status(HttpStatus.CONFLICT)
.body(new ErrorResponse("用户名已存在!!!")); .body(new ErrorResponse("用户名已存在!!!"));
} }
User user = new User(); Users user = new Users();
user.setUsername(registerDTO.getUsername()); user.setUsername(registerDTO.getUsername());
user.setPassword(registerDTO.getPassword()); user.setPassword(registerDTO.getPassword());
user.setEmai(registerDTO.getEmail()); user.setEmail(registerDTO.getEmail());
boolean isSaved = authMapper.insert(user) > 0; // boolean isSaved = authMapper.insert(user) > 0;
boolean isSaved = true;
if (isSaved) { if (isSaved) {
return ResponseEntity return ResponseEntity
.status(HttpStatus.OK) .status(HttpStatus.OK)

View File

@ -1,6 +1,10 @@
package com.yunan.service.impl; package com.yunan.service.impl;
import com.yunan.constant.ResponseCode;
import com.yunan.response.ApiResponse;
import com.yunan.service.EmailService; import com.yunan.service.EmailService;
import com.yunan.util.RedisUtils;
import com.yunan.util.VerificationCodeUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSender;
@ -9,6 +13,7 @@ import org.springframework.stereotype.Service;
import javax.mail.MessagingException; import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMessage;
import java.util.concurrent.TimeUnit;
@Service @Service
public class EmailServiceImpl implements EmailService { public class EmailServiceImpl implements EmailService {
@ -17,24 +22,31 @@ public class EmailServiceImpl implements EmailService {
@Value("${spring.mail.username}") @Value("${spring.mail.username}")
private String from; private String from;
@Autowired
RedisUtils redisUtils;
public ApiResponse<String> sendMail(String email) throws MessagingException {
// 生成验证码
String code = VerificationCodeUtils.generateCode(6);
// 发送邮件
String subject = "注册验证码";
String content = "尊敬的用户,您的验证码为:" + code + ",有效期5分钟,请勿泄漏!";
/**
* 发送邮件
*
* @param to 收件人邮箱
* @param subject 邮件主题
* @param content 邮件内容
*/
public void sendMail(String to, String subject, String content) throws MessagingException {
// 创建邮件消息 // 创建邮件消息
MimeMessage message = mailSender.createMimeMessage(); MimeMessage message = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true); MimeMessageHelper helper = new MimeMessageHelper(message, true);
helper.setFrom(from); helper.setFrom(from);
helper.setTo(to); helper.setTo(email);
helper.setSubject(subject); helper.setSubject(subject);
helper.setText(content, true); helper.setText(content, true);
// 发送邮件 // 发送邮件
mailSender.send(message); mailSender.send(message);
redisUtils.hPutWithExpire("rightCode", email, code, 5, TimeUnit.SECONDS);
return new ApiResponse<>(ResponseCode.SUCCESS, "验证码已发送");
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,3 @@
spring: spring:
application: application:
name: YuNan-demo name: YuNan-demo
@ -11,7 +10,10 @@ spring:
pathmatch: pathmatch:
matching-strategy: ant-path-matcher matching-strategy: ant-path-matcher
---
#****************************mail*************************** #****************************mail***************************
spring:
mail: mail:
# SMTP服务器这个是QQ邮箱的 其他邮箱请另行百度 # SMTP服务器这个是QQ邮箱的 其他邮箱请另行百度
host: smtp.qq.com host: smtp.qq.com
@ -37,9 +39,10 @@ spring:
# 邮件发送时间的限制,单位毫秒 # 邮件发送时间的限制,单位毫秒
writetimeout: 10000 writetimeout: 10000
---
#****************************Redis*************************** #****************************Redis***************************
spring:
redis: redis:
host: localhost # Redis 服务器地址 host: localhost # Redis 服务器地址
port: 6379 # Redis 服务器端口 port: 6379 # Redis 服务器端口

View File

@ -0,0 +1,11 @@
<?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.yunan.mapper.AuthMapper">
<insert id="insertUser" parameterType="com.yunan.dto.RegisterDTO">
insert into users (username, password, email) values (#{username}, #{password}, #{email})
</insert>
<select id="findUserByEmail" resultType="com.yunan.dto.Users">
select * from users where email = #{email}
</select>
</mapper>