在這里記一下。原來的html中的css和js路徑下載不下來,需要換成:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous">
發(fā)送郵件
啟動郵箱的SMTP服務(wù)
我這里使用的是 edu郵箱,好像默認(rèn)開啟了SMTP服務(wù):
配置Spring Email
導(dǎo)入Jar包(Maven)
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-mail -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>3.2.3</version>
</dependency>
配置郵箱參數(shù)
在applications.properties中配置:
# MailProperties
spring.mail.host= mail.ustc.edu.cn
spring.mail.port=465
spring.mail.username=********
spring.mail.password=*******
spring.mail.protocol=smtps
sprint.mail.properties.mail.ssl.enable=true
使用JavaMailSender發(fā)送郵件
- 創(chuàng)建一個包util,表示開發(fā)中需要用到的工具類,并創(chuàng)建MailClient工具類:
@Component
public class MailClient {
private static final Logger logger = LoggerFactory.getLogger(MailClient.class);
@Autowired
private JavaMailSender mailSender;
//從配置文件中把發(fā)件人信息注入進(jìn)來
@Value("${spring.mail.username}")
private String from;
//給to發(fā)送主題為subject,內(nèi)容為content的郵件
public void sendMail(String to, String subject, String content) {
try {
MimeMessage message = mailSender.createMimeMessage();
//使用MimeMessageHelper來協(xié)助構(gòu)建郵件
MimeMessageHelper helper = new MimeMessageHelper(message);
helper.setFrom(from);
helper.setTo(to);
helper.setSubject(subject);
helper.setText(content, true);//true表示支持html格式的郵件
mailSender.send(helper.getMimeMessage());
} catch (MessagingException e) {
logger.error("發(fā)送郵件失?。? + e.getMessage());
}
}
}
- @Component:spring的通用注解,加了這個的類就會被Spring自動管理為bean(比@Service、@Controller之類的更寬泛);
- @Value(“${spring.mail.username}”)表示注解下的變量from的值會從配置文件中讀取。
- mailSender是自帶的JavaMailSender的bean,是SPring用于發(fā)送郵件的工具
- mailSender.createMimeMessage();創(chuàng)建一個MimeMessgge對象來封裝郵件;
- new一個Helper用于往MimeMessage中裝東西(set方法)
- helper.setText(content, true);的true表示支持html格式的郵件
- 創(chuàng)建MailTests類進(jìn)行測試:
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class MailTests {
@Autowired
private MailClient mailClient;
@Test
public void testTextMail() {
mailClient.sendMail("xxxxx","寶寶","寶寶");
}
}
- 可以看到成功發(fā)送了郵件:
使用Thymeleaf發(fā)送HTML郵件
之前已經(jīng)學(xué)會了怎么發(fā)郵件,并把方法封裝到了mailClient.sendMail中,現(xiàn)在我們就要解決參數(shù)content,將其轉(zhuǎn)化成html。
- 創(chuàng)建模版templates/mail/demo.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>郵件示例</title>
</head>
<body>
<p> 歡迎你,<span style="color: red;" th:text="${username}"> </span>!</p>
</body>
</html>
- 這里用th:text把這里的參數(shù)變成可變的,接收username,還加了一點樣式,記得變量名加$。
- 測試發(fā)送郵件:
@Autowired
private TemplateEngine templateEngine;
@Test
public void testHtmlMail() {
Context context = new Context();
context.setVariable("username", "寶寶");
String content = templateEngine.process("/mail/demo", context);//生成的是字符串;
System.out.println(content);
mailClient.sendMail("xxxxxxxxxx","寶寶",content);
}
- 運行的時候Thymeleaf會自己加載模版,但測試時需要自己調(diào)用注入TemplateEngine。
- 使用Context(Thymeleaf的)的setVariable方法裝填內(nèi)容。
- templateEngine.process(“/mail/demo”, context);返回字符串形式的html
開發(fā)注冊功能
- 拆解成:訪問注冊頁面、提交注冊數(shù)據(jù)、激活注冊賬號
- 遵循:數(shù)據(jù)層、業(yè)務(wù)層和視圖層進(jìn)行開發(fā)。
訪問注冊頁面
- 展示頁面,不需要開發(fā)數(shù)據(jù)層和業(yè)務(wù)層
視圖層開發(fā)(controller)
- 創(chuàng)建LoginController類,把site/register的html模版映射到/regesiter路徑
@Controller
public class LoginController {
@RequestMapping(path = "/register", method = RequestMethod.GET)
public String getRegisterPage() {
return "/site/register";
}
}
- 這里的RequestMapping為什么注解方法而不是類:
對于
@RequestMapping
注解的使用,你完全可以只在方法上使用,而不在類上使用。這樣做的話,每個方法都會處理一個特定的URL。
然而,如果你的控制器類有多個方法,而這些方法處理的URL有共同的部分,那么在類上使用
@RequestMapping
注解就會很有用。這樣做可以避免在每個方法上都重復(fù)相同的URL路徑。
例如,假設(shè)你有一個
UserController
類,這個類有getUser
、updateUser
和deleteUser
三個方法,分別用于獲取、更新和刪除用戶。這三個方法處理的URL分別是/user/get
、/user/update
和/user/delete
。你可以在類上使用@RequestMapping("/user")
注解,然后在方法上使用@RequestMapping("/get")
、@RequestMapping("/update")
和@RequestMapping("/delete")
注解,這樣就可以避免在每個方法上都重復(fù)/user
這部分的路徑。
總的來說,是否在類上使用
@RequestMapping
注解,取決于你的具體需求和你的代碼組織方式。
- 注意這里的兩個路徑實際上不一樣:
- @RequestMapping(path = “/register”, method = RequestMethod.GET):這里的/register是URL路徑,當(dāng)用戶通過GET方法訪問/register這個URL時,Spring MVC就會調(diào)用getRegisterPage方法來處理這個請求。這個路徑是相對于應(yīng)用的上下文路徑的,也就是說,如果你的應(yīng)用部署在
http://localhost:8080/myapp
,那么用戶需要訪問http://localhost:8080/myapp/register
來觸發(fā)這個方法。- return “/site/register”;:這里的/site/register是視圖的名稱,它告訴Spring MVC要渲染哪個視圖來生成HTTP響應(yīng)。在Spring MVC中,視圖通常是一個JSP頁面或者是一個Thymeleaf模板。Spring MVC會渲染classpath:/templates/site/register.html這個Thymeleaf模板。
- 修改register.html和index.html,把其中的靜態(tài)的html路徑改成動態(tài)的:
<html lang="en" xmlns:th="http://www.thymeleaf.org">
...
<link rel="stylesheet" th:href="@{/css/global.css}" />
<link rel="stylesheet" th:href="@{/css/register.css}" />
...
<li class="nav-item ml-3 btn-group-vertical">
<a class="nav-link" th:href="@{/index}">首頁</a>
</li>
...
<li class="nav-item ml-3 btn-group-vertical">
<a class="nav-link" th:href="@{/register}">注冊</a>
</li>
- 復(fù)用網(wǎng)頁的上面一層都是一樣的,重復(fù)代碼很麻煩,考慮能不能復(fù)用
在index.html的header上添加fragment標(biāo)簽為該片段命名:
<header class="bg-dark sticky-top" th:fragment="header">
在register.html上復(fù)用:
<header class="bg-dark sticky-top" th:replace="index :: header">
- 展示頁面:
提交注冊數(shù)據(jù)
- 首先創(chuàng)建一個工具類,用幾個靜態(tài)方法用于生成隨機(jī)字符串和對key進(jìn)行md5加密:
public class CommunityUtil {
//生成隨機(jī)字符串
public static String generateUUID() {
return java.util.UUID.randomUUID().toString().replaceAll("-", "");
}
//MD5加密
public static String md5(String key) {//key是原始密碼加鹽
if(StringUtils.isBlank(key)) {//判斷key是否為空或者長度為0
return null;
}
return DigestUtils.md5Hex(key.getBytes());
}
}
驗證賬號是否存在
- UserService.java中將該注入的注入(需要發(fā)郵件要client和模版引擎,以及域名和路徑)
@Autowired
private MailClient mailClient;
@Autowired
private TemplateEngine templateEngine;
@Value("${community.path.domain}")
private String domain;
@Value("${server.servlet.context-path}")
private String contextPath;
- 編寫register方法框架
public Map<String, Object> register(User user) {//用Map封裝錯誤信息返回給客戶端
Map<String, Object> map = new HashMap<>();
//1. 驗證用戶是否符合要求
if (user == null) {
throw new IllegalArgumentException("User參數(shù)不能為空");
}
if (user.getUsername() == null) {//業(yè)務(wù)上的漏洞
map.put("usernameMsg", "用戶名不能為空");
return map;
}
if (user.getPassword() == null) {
map.put("passwordMsg", "密碼不能為空");
return map;
}
if (user.getEmail() == null) {
map.put("emailMsg", "郵箱不能為空");
return map;
}
...
}
- 要求傳入一個User
- 將錯誤信息通過map傳出來;
- usernameMsg等xxMsg在后面的thymeleaf模版上要用。
- 驗證賬號
//驗證賬號和郵箱是否存在
if (userMapper.selectByName(user.getUsername()) != null) {
map.put("usernameMsg", "該用戶名已存在");
return map;
}
if (userMapper.selectByEmail(user.getEmail()) != null) {
map.put("emailMsg", "該郵箱已被注冊");
return map;
}
- 注冊用戶
- 這里的邏輯是符合就創(chuàng)建用戶,但是顯示未激活
//2. 注冊用戶
//生成salt
user.setSalt(CommunityUtil.generateUUID().substring(0, 5));
//加密密碼
user.setPassword(CommunityUtil.md5(user.getPassword() + user.getSalt()));
//設(shè)置用戶類型
user.setType(0);
//設(shè)置用戶狀態(tài)
user.setStatus(0);
//設(shè)置激活碼
user.setActivationCode(CommunityUtil.generateUUID());
//設(shè)置頭像
user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png", (int) (Math.random() * 1000)));
//設(shè)置創(chuàng)建時間
user.setCreateTime(new Date());
userMapper.insertUser(user);
發(fā)送激活郵件
//3. 發(fā)送激活郵件
//構(gòu)建郵件內(nèi)容
Context context = new Context();
context.setVariable("email", user.getEmail());
//Mybatis會自動將user對象回填id
context.setVariable("url", domain + contextPath + "/activation/" + user.getId() + "/" + user.getActivationCode());
String content = templateEngine.process("/mail/activation", context);
mailClient.sendMail(user.getEmail(), "激活賬號", content);
return map;
- 使用context構(gòu)建thyme模版需要裝填的信息。
- context.setVariable把xx變量設(shè)置為xx;
- 這里注意與改th標(biāo)簽然后用model.addAttribute方法不用,因為這是用thyme生成html還不是與客戶端交互
這一步要修改html文件。
- 發(fā)送郵件的模版mail/activation.html修改成模版
- 換成thymeleaf模版
<html lang="en" xmlns:th="http://www.thymeleaf.org">
- 替換email為變量
<b th:text="${email}">xxx@xxx.com</b>, 您好!
- 替換url為變量:
<p>
您正在注冊, 這是一封激活郵件, 請點擊
<a th:href= "${url}">此鏈接</a>,
激活您的賬號!
</p>
這里的變量由哪里傳遞?回看第三步發(fā)送激活郵件。文章來源:http://www.zghlxwxcb.cn/news/detail-839271.html
編寫controller
@Controller
public class LoginController {
@Autowired
private UserService userService;
@RequestMapping(path = "/register", method = RequestMethod.GET)
public String getRegisterPage() {
return "site/register";
}
@RequestMapping(path = "/register", method = RequestMethod.POST)
public String register(Model model, User user) {
Map<String, Object> map = userService.register(user);
if(map == null || map.isEmpty()){
model.addAttribute("msg", "注冊成功,我們已向您的郵箱發(fā)送了一封激活郵件,請盡快激活!");
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";
}
}
}
- register傳入一個User
- 調(diào)用userService.register查看信息選擇怎么和瀏覽器響應(yīng)。
- 成功返回跳轉(zhuǎn)界面,不成功留在注冊。
修改operate-result
- thymeleaf,混入變量msg和target(從model.addAttribute得到)
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<!-- 內(nèi)容 -->
<div class="main">
<div class="container mt-5 pt-5">
<div class="jumbotron">
<p class="lead" th:text="${msg}"></p>
<hr class="my-4">
<p>
系統(tǒng)會在 <span id="seconds" class="text-danger">8</span> 秒后自動跳轉(zhuǎn),
您也可以點此 <a id="target" th:href="${target}" class="text-primary">鏈接</a>, 手動跳轉(zhuǎn)!
</p>
</div>
</div>
</div>
修改register.html
- 引入thymeleaf:
<html lang="en" xmlns:th="http://www.thymeleaf.org">
- 復(fù)用header:
<header class="bg-dark sticky-top" th:replace="index :: header">
- 主要修改表單,method設(shè)定為POST,路徑提交到register(thymeleaf語法,是Mapping的路徑不是html)
<form class="mt-5" method="post" th:action="@{/register}"> <!-- 注冊表單 -->
- 如果usernameMsg沒問題,就不報錯,不然把is-invalid拼到前面讓前端報錯,所在的值如果其他地方錯了,這里應(yīng)該保持show
<input type="text" th:class="|form-control ${usernameMsg!=null?'is-invalid':''}|"
th:value="${user!=null? user.username : ''}"
id="username" name="username" placeholder="請輸入您的賬號!" required>
<div class="invalid-feedback" th:text="${usernameMsg}">
該賬號已存在!
</div>
- password:
<input type="password" th:class="|form-control ${passwordMsg!=null?'is-invalid':''}|"
th:value="${user!=null? user.password : ''}"
id="password" name="password" placeholder="請輸入您的密碼!" required>
<div class="invalid-feedback" th:text="${passwordMsg}">
密碼長度不能小于8位!
</div>
- email:
<input type="email" th:class="|form-control ${emailMsg!=null?'is-invalid':''}|"
th:value="${user!=null? user.email : ''}"
id="email" name="email" placeholder="請輸入您的郵箱!" required>
<div class="invalid-feedback" th:text="${emailMsg}">
該郵箱已注冊!
</div>
激活注冊賬號
到第二個視頻的13:26處開始,明天再記錄。文章來源地址http://www.zghlxwxcb.cn/news/detail-839271.html
到了這里,關(guān)于Day18: 發(fā)送郵件、開發(fā)注冊功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!