赞
踩
邮件功能,在用户注册时,用于验证用户邮箱并激活用户账号,用户输入正确邮箱地址并注册成功之后,需要向用户注册邮箱发送激活邮件。本功能旨在实现向指定邮箱发送邮件的功能。
开通发送方邮箱的SMTP协议,如下图为QQ邮箱,设置完成后,保存更改
在项目pom.xml文件中导入对应的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
在 application.properties 中配置邮箱的相关设置,这里演示的是qq邮箱的相关配置。
# MailProperties
spring.mail.host=smtp.qq.com
spring.mail.port=465
#自己的邮箱账号
spring.mail.username=111111111@qq.com
#邮箱授权码,邮箱设置页面生成,并不是邮箱登录密码
spring.mail.password=********
spring.mail.protocol=smtp
spring.mail.test-connection: true
spring.mail.default-encoding=utf-8
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.port:${spring.mail.port}
spring.mail.properties.mail.smtp.auth:true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
在community包下新建util工具包,在工具类 util 包下创建 MailClient类,用于发送邮件:
@Component public class MailClient { /**定义日志记录信息*/ private static final Logger logger = LoggerFactory.getLogger(MailClient.class); /**注入发送邮件的Java类*/ @Autowired private JavaMailSender mailSender; /**注意这个括号一定要是花括号*/ @Value("${spring.mail.username}") private String from; /** * 发送邮件 * @param to 发送对象 * @param subject 发送主题 * @param content 发送内容 */ public void sendMail(String to, String subject, String content){ try { /**创建发送的邮件类模版*/ MimeMessage mimeMessage = mailSender.createMimeMessage(); /**根据邮件类模版创建邮件生成类*/ MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage); /**设置发送邮件的邮件信息*/ mimeMessageHelper.setFrom(from); mimeMessageHelper.setTo(to); mimeMessageHelper.setSubject(subject); mimeMessageHelper.setText(content,true); /**发送邮件*/ mailSender.send(mimeMessageHelper.getMimeMessage()); } catch (MessagingException e) { logger.error("发送邮件报错 :" + e.getMessage()); } } }
在test包下创建MailTests类,对发送邮件功能进行测试
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class MailTest {
@Autowired
private MailClient mailClient;
@Test
public void testTextMail(){
mailClient.sendMail("目标邮箱","test","welcome");
}
}
检查目标邮箱是否收到对应主题和内容
在MailTests测试类中添加testHtmlMail测试方法,thymeleaf模版文件demo.html在项目源码中。
@Test
public void testHtmlMail() {
Context context = new Context();
context.setVariable("username", "Tom");
String content = templateEngine.process("/mail/demo", context);
System.out.println(context);
mailClient.sendMail("目标邮箱","HTML",content);
}
检查目标邮箱是否收到对应主题和内容
用户注册功能,用户点击注册按钮,跳转至注册页面;
输入用户名,密码,邮箱信息;
用户名判空、验证是否已经注册过,密码判空、进行加密处理,邮箱判空、验证是否正确邮箱格式、验证是否已经注册过;
用户注册,插入新用户;
用户激活,向用户注册邮箱发送激活链接;
激活成功后,跳转到登录界面;
修改index.html中注册链接,利用thymeleaf实现界面跳转至注册网页register.html,前端修改内容详见源代码。
在 util 包下添加 CommunityUtil工具类,这里主要是生成随机字符串、 md5 加密和验证邮箱合法性
public class CommunityUtil { /** * 生成随机字符串,用于随机密码和随机命名 * @return */ public static String generateUUID(){ return UUID.randomUUID().toString().replaceAll("-",""); } /** * MD5加密,密码+salt * @param key * @return */ public static String MD5(String key){ if(StringUtils.isBlank(key)){ return null; } return DigestUtils.md5DigestAsHex(key.getBytes()); } /** * 验证邮箱是否合法 * @param string * @return */ public static boolean isEmail(String string) { if (string == null){ return false; } String regEx1 = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"; Pattern p; Matcher m; p = Pattern.compile(regEx1); m = p.matcher(string); if (m.matches()){ return true; }else{ return false; } } }
util包下添加 CommubityConstant 接口,返回激活的三种状态,代码如下:
public interface CommunityConstant {
/**
* 激活成功
*/
int ACTIVATION_SUCCESS = 0;
/**
* 重复激活
*/
int ACTIVATION_REPEAT = 1;
/**
* 激活失败
*/
int ACTIVATION_FAILURE = 2;
}
在application.properties添加配置文件
# community
community.path.domain=http://localhost:8080
在 service 包下的 UserService 类中添加 register 和 activation 方法分别用于提供注册和激活服务,sendMail用户给指定用户发送邮件,相关代码如下:
@Service public class UserService implements CommunityConstant { @Autowired private UserMapper userMapper; @Autowired private MailClient mailClient; @Autowired private TemplateEngine templateEngine; @Value("${community.path.domain}") private String domain; @Value("${server.servlet.context-path}") private String contextPath; /** * 根据用户id查询用户 * @param id * @return */ public User findUserById(int id) { return userMapper.selectById(id); } /** * 用户注册 * @param user * @return */ public Map<String, Object> register(User user) { Map<String, Object> map = new HashMap<>(); //用户、账号、密码、邮箱判空 if (user == null) { throw new IllegalArgumentException("参数不能为空!"); } if (StringUtils.isBlank(user.getUsername())) { map.put("usernameMsg", "账号不能为空!"); return map; } if (StringUtils.isBlank(user.getPassword())) { map.put("passwordMsg", "密码不能为空!"); return map; } if (StringUtils.isBlank(user.getEmail())) { map.put("emailMsg", "邮箱不能为空!"); return map; } // 验证邮箱合法性 boolean email = CommunityUtil.isEmail(user.getEmail()); if(!email){ map.put("emailMsg","邮箱不正确!"); return map; } // 验证账号是否已注册 User u = userMapper.selectByName(user.getUsername()); if (u != null) { map.put("usernameMsg", "该账号已存在!"); return map; } // 验证邮箱是否已注册 u = userMapper.selectByEmail(user.getEmail()); if (u != null) { map.put("emailMsg", "该邮箱已被注册!"); return map; } // 注册用户 user.setSalt(CommunityUtil.generateUUID().substring(0, 5)); user.setPassword(CommunityUtil.MD5(user.getPassword() + user.getSalt())); user.setType(0); user.setStatus(0); user.setActivationCode(CommunityUtil.generateUUID()); user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png", new Random().nextInt(1000))); user.setCreateTime(new Date()); userMapper.insertUser(user); return map; } /** * 向指定用户发送邮件 * @param username 用户名 */ public void sendMail(String username){ User user = userMapper.selectByName(username); /**设置邮件模版*/ Context context = new Context(); context.setVariable("email",user.getEmail()); /**设置处理请求的路径*/ //http://localhost:8086/community/activation/userId/code String url = domain + contextPath + "/activation/" + user.getId() + "/" + user.getActivationCode(); context.setVariable("url",url); String process = templateEngine.process("/mail/activation", context); mailClient.sendMail(user.getEmail(),"激活账号",process); } /** * 用户激活邮件 * @param userId * @param code * @return */ public int activation(int userId, String code) { User user = userMapper.selectById(userId); if (user.getStatus() == 1) { return ACTIVATION_REPEAT; } else if (user.getActivationCode().equals(code)) { userMapper.updateStatus(userId, 1); return ACTIVATION_SUCCESS; } else { return ACTIVATION_FAILURE; } } }
在 controller 包下创建 LoginController 类,用户接受前端发送过来的注册请求,代码如下:
@Controller public class LoginController implements CommunityConstant { private static final Logger logger = LoggerFactory.getLogger(LoginController.class); @Autowired private UserService userService; /** * 获取注册页面 * @return */ @GetMapping("/register") public String getRegisterPage() { return "/site/register"; } /** * 获取登录页面 * @return */ @GetMapping("/login") public String getLoginPage() { return "/site/login"; } /** * 用户注册 * @param model * @param user * @return * @throws IllegalAccessException */ @PostMapping("/register") public String register(Model model, User user) throws IllegalAccessException { Map<String, Object> map = userService.register(user); /**map为空或者为null,无报错信息*/ if (map == null || map.isEmpty()) { userService.sendMail(user.getUsername()); model.addAttribute("msg", "注册成功,我们已经向您的邮箱发送了一份激活邮件,请尽快激活!"); model.addAttribute("target", "/index"); return "/site/operate-result"; } else { model.addAttribute("usernameMsg", map.get("usernameMsg")); model.addAttribute("passwordMsg", map.get("passwordMsg")); model.addAttribute("emailMsg", map.get("emailMsg")); return "/site/register"; } } /** * 激活账号 * @param model * @param userId * @param code * @return */ // http://localhost:8080/community/activation/101/code @GetMapping("/activation/{userId}/{code}") public String activation(Model model, @PathVariable("userId") int userId, @PathVariable("code") String code) { int result = userService.activation(userId, code); if (result == ACTIVATION_SUCCESS) { model.addAttribute("msg", "激活成功,您的账号已经可以正常使用了!"); model.addAttribute("target", "/login"); } else if (result == ACTIVATION_REPEAT) { model.addAttribute("msg", "无效操作,该账号已经注册过了!"); model.addAttribute("target", "/index"); } else { model.addAttribute("msg", "激活失败,您提供的激活码不正确!"); model.addAttribute("target", "/index"); } return "/site/operate-result"; } }
启动该项目,进入注册页面,填写相关的信息;
点击激活链接,激活用户账号;
激活成功,跳转至登录界面;
为了方式批量注册,需要开发验证码功能,防止机器人自动注册、批量注册,本项目采用Kaptcha,Kaptcha 是一个可高度配置的实用验证码生成工具。
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
在 config 包下创建 Kaptcha 类,编写 Kaptcha 所需的配置信息,代码如下:
@Configuration public class KaptchaConfig { @Bean public Producer kaptchaProducer() { Properties properties = new Properties(); /**配置验证码*/ properties.setProperty("kaptcha.image.width", "100"); properties.setProperty("kaptcha.image.height", "40"); properties.setProperty("kaptcha.textproducer.font.size", "32"); properties.setProperty("kaptcha.textproducer.font.color", "0,0,0"); // 在哪个字符串中生成验证码 properties.setProperty("kaptcha.textproducer.char.string", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYAZ"); properties.setProperty("kaptcha.textproducer.char.length", "4"); properties.setProperty("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise"); DefaultKaptcha kaptcha = new DefaultKaptcha(); Config config = new Config(properties); kaptcha.setConfig(config); return kaptcha; } }
在 LoginController 类中添加 getKaptcha 方法,代码如下:
@Autowired private Producer kaptchaProducer; /** * 获取验证码 * @param response * @param session */ @GetMapping("/kaptcha") public void getKaptcha(HttpServletResponse response, HttpSession session) { // 生成验证码 String text = kaptchaProducer.createText(); BufferedImage image = kaptchaProducer.createImage(text); // 将验证码存入session session.setAttribute("kaptcha", text); // 将图片输出给浏览器 response.setContentType("image/png"); try { OutputStream os = response.getOutputStream(); ImageIO.write(image, "png", os); } catch (IOException e) { logger.error("响应验证码失败:" + e.getMessage()); } }
前端对生成验证码以及刷新验证码进行修改,详情见源代码;
启动项目,查看验证码是否正确显示,点击刷新刷新验证码;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。