pringBoot使用Thymeleaf模板(2019-09-25)
2017年的時候就接觸了SpringBoot,但是從接觸之初到最近基本是沒有用過Thymeleaf的,一方面自己覺得SpringBoot單純用作接口開發就行了,另一方面自己也略懂前端,通常會用靜態Html或者Vue和Angular來做一些小測試。
但是最近因為在做自己個人網站,其中一個模塊是項目展示,準備展示的第一個項目就是郵件的發送,郵件發送的接口很早之前就封裝過,剩下就是頁面了,一開始想的是寫html通過ajax訪問接口,但是數據渲染又很麻煩,要通過JQ去渲染,而如果通過Vue,我又覺得太麻煩,搭建Vue,配置代理,壓縮打包文件等等,所以感覺給自己造成挺大的負擔,于是想到Thymeleaf這個模板,在網上搜索一些知識,就決定結合Thymeleaf來做郵件項目的頁面,這樣數據輸出頁面可以使用模板的表達式,相比純html的數據渲染要簡單,相比Vue又不那么重。
其使用方言很簡單,通過th:text="..."就可以對后端返回數據進行渲染。
而且其表達式語法有五種類型
${...} : 變量表達式。 *{...} : 選擇表達式。 #{...} : 消息 (i18n) 表達式。 @{...} : 鏈接 (URL) 表達式。 ~{...} : 片段表達式。
其他相關概念可以去網上看Thymeleaf教程,下面說一下SpringBoot使用Thymeleaf模板的過程
關于Thymeleaf的原理簡單的說就是通過Controller找到響應的模板文件,然后根據模板表達式算法把 Controller 輸出的對象匹配到模板表達式中,從而展示了頁面。
使用的過程挺簡單:
首先引入依賴
<!--引入thymeleaf的依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
然后修改配置文件(如果你習慣空格再換行,那就注意下面的注釋)
# 默認路徑,注意不能少反斜杠,也不能在反斜杠后面多一些空格 spring.thymeleaf.prefix=classpath:/templates/ # 后綴 spring.thymeleaf.suffix=.html # 緩存 spring.thymeleaf.cache=false
template下建立index.html,然后書寫Controller
項目名稱:01-spring-boot-MVC
@SpringBootApplication 用在 SpringBoot 項目的啟動程序上,整個 SpringBoot 只有且必須有一個這樣的注解,是項目的入口程序。
如下代碼所示:
源代碼:src/main/java/com/springboot/codingstudty/MainApplication.java
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run (Demo01Application.class, args);
}
}
復制代碼
@SpringBootApplication 是以下 3 個注解的整合:
@Configuration
@EnableAutoConfiguration
@ComponentScan
復制代碼
@SpringBootApplication 同等于這 3 個注解,以上清單也有介紹。
@Controller 是讓 URL 請求返回具體的頁面,如返回 html、jsp 頁面等。這個注解在類頭上添加。
如下是“http://localhost 跳轉到 index.html”示例,需要 3 步驟完成。
(1)要讓 SpringBoot 中能訪問到 HTML、JSP 等頁面,需要在 application.properties 配置
源代碼:src/main/resources/application.properties
#默認找到 static 下,只需如下配置即可:
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html
復制代碼
(2)在 static 下創建 index.html
源代碼:src/main/resources/static/index.html
<div>
<h3>首頁</h3>
<div>首頁的內容。。。。。</div>
</div>
復制代碼
(3)編寫 CodingStudyIndexController 控制器
源代碼:
src/main/java/com/springboot/codingstudty/controller/CodingStudyIndexController.java
@Controller
public class CodingStudyIndexController {
}
復制代碼
(4)配合@RequestMapping 進行具體頁面跳轉控制:
跳轉到 index.html 頁面
源代碼:
src/main/java/com/springboot/codingstudty/controller/CodingStudyIndexController.java
/**
* 沒有數據渲染的返回
* @return
*/
@RequestMapping("/")
public String index01() {
return "index";
}
復制代碼
注意:Controller 數據渲染到頁面上需要返回 ModelAndView 類型,如下:
源代碼:
src/main/java/com/springboot/codingstudty/controller/CodingStudyIndexController.java
/**
* 返回 ModelAndView
* 通過 ModelAndView 可以帶入數據,并渲染到頁面
* @return
*/
@RequestMapping("/index")
public ModelAndView index(){
ModelAndView modelAndView=new ModelAndView ();
//可以設置數據
String data="這個數據來自 IndexController...";
modelAndView.addObject("data",data);
//跳轉到 index.html 頁面
modelAndView.setViewName ("index");
return modelAndView;
}
復制代碼
此時,在 index.html 頁面獲取 data 數據,有多種方案。
由于第一種方案的語法簡單,使用頻率高,下面簡單說第一種方案。
在 pom.xml 中引入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
復制代碼
在 application.properties 配置:
##################freemarker 模板配置
#后綴
spring.freemarker.suffix=.html
#默認在 templates 下
spring.freemarker.template-loader-path=classpath:/static/
#req 訪問 request
spring.freemarker.request-context-attribute=req
spring.freemarker.content-type=text/html
spring.freemarker.enabled=true
復制代碼
這樣配置之后,在 index.html 中獲取 data 數據的代碼是:
<div>
<h3>首頁</h3>
<div>首頁的內容.${data}</div>
</div>
復制代碼
由于本章重點不是介紹 freemarker 如何使用,這里點到為止。
還有一些注意的地方:讓@Controller 能找到頁面的前提是需要配置路徑,配置映射 HTML頁面有多種方案,下面介紹四種方案:
1)默認放在 static 下:
#映射 html 頁面
#========1、默認===============================#默認找到 static 下,只需如下配置即可:
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html
復制代碼
2)指向新的路徑,如 views 路徑下
#當然可以改變 static-locations 映射路徑,如下:
#========2、會在 views 下找文件====================spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html
spring.resources.static-locations=classpath:/views/
復制代碼
3)指向新的路勁,如 public 路徑下
#========3、會在 public 下找文件====================spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html
spring.resources.static-locations=classpath:/public/
復制代碼
4)指向新的路勁,如 ENTA-INF/resource 下
#========4、會在/META-INF/resources/下找文件======spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html
spring.resources.static-locations=classpath:/META-INF/resources/
復制代碼
不管怎么設置,以上路徑必須在 src/main/resource 下.
@RestController 是 新 增 的 注 解 , 是 @Controller 和 @ResponseBody 組 合 。
@RestController 注解后,其方法內再配合@RequestMapping,即可返回 Json 格式的數據。
(1) 新建 CodingStudyRestController 控制器:
源代碼:
src/main/java/com/springboot/codingstudty/controller/CodingStudyRestController.java
@RestController
public class CodingStudyRestController {
/**
* 假設是獲取用戶信息
* @return
*/
@GetMapping("user")
public Map<String,Object> getUser() {
//模擬一個用戶
Map<String,Object> user=new HashMap<>();
user.put ("id",1);
user.put ("name","張三");
user.put ("age",18);
//返回這個用戶
return user;
}
}
復制代碼
運行結果:
@RequestMapping 注解要在 Controller 控制器中的方法頭使用,如下:
源代碼:src/main/java/com/springboot/codingstudty/controller/CodingStudyIndexController.java
@RequestMapping("/index")
public ModelAndView index(){
ModelAndView modelAndView=new ModelAndView ();
//可以設置數據
String data="這個數據來自 IndexController...";
modelAndView.addObject("data",data);
//跳轉到 index.html 頁面
modelAndView.setViewName ("index");
return modelAndView;
}
復制代碼
Spring Boot 有 GetMapping、PostMapping、PutMapping、DeleteMapping 代替它。
在參數前面設置,格式是:
@RequestParam(value=“變量名”, required=true/false, defaultVale=默認值 )
復制代碼
設置 required=false
舉例,新建 RequestParamController 控制器:
源代碼:
src/main/java/com/springboot/codingstudty/controller/RequestParamController.java
@GetMapping("param")
public String param(
@RequestParam("id") String id,
@RequestParam(value="name", required=false) String name,
@RequestParam(value="age", required=false) int age){
String data="";
try {
//返回ID,NAME,age
data="id=" + id + ",name=" + name + ",age=" + age;
} catch (Exceptione){
data=e.getMessage();
}
return data;
}
復制代碼
第一參數:如下 url 必須有 id 這個參數,否則報錯(即:?id=1)。
@RequestParam("id") String id
復制代碼
第二個參數:如下 url 可以沒有 userName 這個參數,請求不報錯。
@RequestParam(value="userName", required=false) String userName
復制代碼
第三個參數:如下設置 required=false,age 不傳值,此時 age 等于 null,因 int 是基礎類型不能接收 null 所以報錯,所以一般可以使用 Integer 聲明,避免錯誤。
@RequestParam(value="age", required=false) int age
復制代碼
運行結果:
新建 PathVariableController 控制器類。
源代碼:
src/main/java/com/springboot/codingstudty/controller/PathVariableController.java
在參數前面設置,格式是:
@PathVariable(value=“變量名”, required=true/false)
復制代碼
拋出異常(可選配置)
具體方法:
@GetMapping("path/{id}/{name}")
public String pathVar(
@PathVariable("id") String id,
@PathVariable(value="name",required=false) String userName){
return "id="+id+",userName="+userName;
}
復制代碼
傳遞參數:如:http://localhost:8086/path/1/張三
注意:請求路徑必須是完整,否則報錯。
運行結果
以下@GetMapping、@PostMapping、@PutMapping、@DeleteMapping 測試示例,新建一個控制器類:UserController
源代碼:
src/main/java/com/springboot/codingstudty/controller/UserController.java
@GetMapping 是一個組合注解,是@RequestMapping(method=RequestMethod.GET)的縮寫,只接收前端 get 請求。
@GetMapping
public Map<String,Object> getUser() {
Map<String,Object> user=new HashMap<>();
user.put("id",1);
user.put("name","ming206");
return user;
}
復制代碼
@PostMapping 是一個組合注解,是@RequestMapping(method=RequestMethod.POST)的縮寫,只接收前端 post 提交,一般用于數據的新增。
@PostMapping
public boolean insert(@RequestBody User user) {
//insert ...
return true;
}
復制代碼
@PutMapping 是一個組合注解,是@RequestMapping(method=RequestMethod.PUT)的縮寫,只接收前端 PUT 提交,一般用于數據的修改。
@PutMapping
public boolean update(@RequestBody User user) {
//update .....
return true;
}
復制代碼
@DeleteMapping 是一個組合注解,是@RequestMapping(method=RequestMethod.DELETE)的縮寫,只接收前端 DELETE 提交,用于數據刪除。
@DeleteMapping
public boolean del(@PathVariable("id") String id) {
System.out.println(id);
//delete ....
return true;
}
復制代碼
@ResponseBody 注解通常使用在控制層(controller)的方法上,其作用是將方法的返回值以特定的格式寫入到 response 的 body 區域,進而將數據返回給客戶端。當方法上面沒有寫 ResponseBody,底層會將方法的返回值封裝為 ModelAndView 對象。
在 Spring Boot 的@RestController 中就不需要再加這個注解了,上面提到@RestController是@controller 和@ResponseBody 的組合,請閱讀 RestController。
如下是在@Controller 修飾的類(控制器類)里的方法體前面加這個注解:
源代碼:src/main/java/com/springboot/codingstudty/controller/UserViewController.java
@GetMapping("json")
@ResponseBody
public Map<String,Object> getJson(){
//模擬一個用戶
Map<String,Object> user=new HashMap<> ();
user.put ("id",100);
user.put("name","ResponseBody");
user.put("age",25);
//返回這個用戶
return user;
}
復制代碼
運行結果:
@RequestBody 主要用來接收前端傳遞給后端的 json 字符串中的數據的(請求體中的數據的);GET 方式無請求體,所以使用@RequestBody 接收數據時,前端不能使用 GET 方式提交數據,而是用 POST 方式進行提交。
在后端的同一個接收方法里,@RequestBody 與@RequestParam()可以同時使用,@RequestBody 最多只能有一個,而@RequestParam()可以有多個。
舉例:
源代碼:src/main/java/com/springboot/codingstudty/controller/UserController.java
@PutMapping
public boolean update(@RequestBody User user) {
//update .....
return true;
}
@PostMapping("save")
public String save(
@RequestParam("id") String id,
@RequestParam(value="age", required=false) int age,
@RequestBody User user){
return "id="+id+",age="+age+"。user 對象==>"+user.toString ();
}
復制代碼
User 模型:
@Data
public class User {
int id;
String name;
String age;
}
復制代碼
運行結果:
以上 API 測試工具是 PostMan
前后端分離之后前端 Ajax 請求后端經常碰到的問題就是跨域問題。可以有多種方式解決這個問題,下面介紹 2 個解決方法:
方法 1:在方法頭加@CrossOrigin 注解
@GetMapping("isCheck")
@CrossOrigin
public R<List<Resource>> selectAll(@RequestParam("ids") String ids) {
return R.ok (this.resourceService.getListByIds (ids));
}
復制代碼
方法 2:使用過濾器設置:
源代碼: src/main/java/com/springboot/codingstudty/configuration/AccessControlAllowOriginFilter.java
package com.springboot.codingstudty.configuration;
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 解決跨域問題
*/
@Configuration
public class AccessControlAllowOriginFilter implements Filter {
@Override
public void doFilter( ServletRequest req,
ServletResponse res,
FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response=(HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods","POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, response);
}
public void init(FilterConfig filterConfig) {
System.out.println("初始化配置......");
}
public void destroy() {
System.out.println("銷毀......");
}
}
復制代碼
@Configuration 是定義配置類,一般在該類內部通過@bean 注冊,也就是說將來在調用時,不需要手工 new。下面我們按照 3 步驟試一試。
(1)定義一個類,這是一個普通類。
源代碼:src/main/java/com/springboot/codingstudty/configuration/UserAction.java
public class UserAction {
public String display(){
return "執行 UserAction display.... ";
}
}
復制代碼
(2)定義配置類,并注冊 bean
源代碼:src/main/java/com/springboot/codingstudty/configuration/MyConfiguration.java
@Configuration
public class MyConfiguration {
//默認
@Bean
UserAction userAction(){
System.out.println ("默認名字是 userAction");
return new UserAction();
}
//……
}
復制代碼
注意:
(3) 調用 UserAction 類
在 Controller 類上調用測試。注意不管在哪里調用,最終運行必須依賴于 Spring 容器,否則是運行不了的。例如在普通的 main 方法中是報空指針異常的,但是在 Controller、Test測試類上是可以的,因為它們的環境都是依賴于 Spring 容器。
調用時在變量上加注解@Autowired,即可取到 bean 實例。
創建 UserActionController 類
源代碼:
src/main/java/com/springboot/codingstudty/controller/UserActionController.java
//加了 Autowired 注解后,不需要 new 對象
@Autowired
UserAction userAction;
@GetMapping("user/display")
public String getDisplay() {
return userAction.display();
}
復制代碼
在瀏覽器端請求打印效果:
也可以手工編寫獲取 bean 的方法,下面新建一個類,CreateBean 類
源代碼:src/main/java/com/springboot/codingstudty/configuration/CreateBean.java
@Component
public class CreateBean implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {this.applicationContext=applicationContext;}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
}
復制代碼
此時,在 UserActionController 內調用:
源代碼:src/main/java/com/springboot/codingstudty/controller/UserActionController.java
@Autowired
CallBean callBean;
@GetMapping("user/display2")
public String getDisplay2(){
//注冊 bean 時的名字,是一個字符串
String beanName="userAction";
UserAction userAction=callBean.getApplicationContext ()
.getBean (beanName,UserAction.class);
String msg=userAction.display ();
return "手工獲取 bean==》"+msg;
}
復制代碼
在瀏覽器端請求打印效果:
以上已經多次使用到@Bean 注解,這里就不多介紹了,直接上示例吧。
(1)默認注冊 bean,以上的代碼也有,如下
源代碼:src/main/java/com/springboot/codingstudty/configuration/MyConfiguration.java
//默認
@Bean
UserAction userAction(){
System.out.println ("默認名字是 userAction");
return new UserAction();
}
復制代碼
(2)指定一個 bean 名字
源代碼:src/main/java/com/springboot/codingstudty/configuration/MyConfiguration.java
@Bean(value="userAction1")
UserAction userAction1(){
System.out.println ("名字為 userAction1");
return new UserAction();
}
復制代碼
(3)調用是制定 bean 的名字
源代碼:src/main/java/com/springboot/codingstudty/controller/UserActionController.java
用@Resource
@Resource(name="userAction1")
UserAction userAction;
復制代碼
或@Autowired+@Qualifier
@Autowired
@Qualifier(value="userAction1")
UserAction userAction;
復制代碼
用于修飾 service 層的組件,標注在類上。注意不是標在接口上。
/**
* 描述:service 層
* @author ming
*/
@Service
public class UserService {
//TODO
}
復制代碼
之后,調用時和用@Bean 注冊是一樣用@Autowired 即可。
用@Service 標注的類一般都是明確是業務服務層,從業務角度清晰的劃分。
@component 和@Service 沒有本質的區別,@Service 內部還是去引用了@component,他們是沒有什么區別的。
業務無法明確劃分或不能歸類清晰時,對該功能進行組件封裝,并希望交給 IOC 管理,這時候用@component 注解。@component 和@Service 僅僅是從業務功能上有所劃分,他們的本質都是“把對象的生命周期交給 IOC 管理”的目的。
例如下面這個示例,使用@component 注解
源代碼:src/main/java/com/springboot/codingstudty/configuration/CreateBean.java
@Component
public class CreateBean implements ApplicationContextAware {
//……
}
復制代碼
@Repository 和@Controller、@Service、@Component 的作用差不多,都是把對象交給 IOC管理。@Repository 用在持久層的接口上,這個注解是將接口的一個實現類交給 spring 管理,使用了@Repository 注解后,就具備可以將原生的數據庫異常轉為 Spring 處理得異常。
有兩個地方需要這個注解,在普通的 Spring 項目中的持久層和在使用 JPA 時的接口上使用,在 Spring Boot 項目中更多的是使用在 JPA 接口上。
在 JPA 接口上的使用如下:
/**
* 描述:dao 層
* @author ming
*/
@Repository
public interface UserDao extends JpaRepository<User,String>{
//TODO
}
復制代碼
有時候不用@Repository 來注解,也可以得到這個接口的實現類,有幾個原因:
例如使用 SSM 框架時候,經常在 Dao 層注入@Mapper 即可(這時候需要引入 MyBatis 或者 MyBatisPlus 依賴包)。
在上面提到多次@Autowired,是用來“new 實例”的。加了該注解的對象直接調用即可,無需手工 new 對象。
//注意,加了@Autowired 就相當于 new UserAction
@Autowired
UserAction userAction;
復制代碼
當多個同類型 bean 時,可以這樣使用@Resource,如下介紹.
用@Resource 和@Autowired 類似
@Resource(name="userAction1")
UserAction userAction;
復制代碼
@Autowired+@Qualifier
@Autowired
@Qualifier(value="userAction1")
UserAction userAction;
復制代碼
@Value 是獲取 application.properties 中的配置信息,例如 application.properties 中有相關的配置如下:
(1)application.properties:
server.port=8086
spring.datasource.url=jdbc:mysql://localhost:3309/db01
復制代碼
(2)用@Value 取值
新建控制器類 ValueController
源代碼:src/main/java/com/springboot/codingstudty/controller/ValueController.java
@RestController
public class ValueController {
@Value("${server.port}")
public String port;
public static String DATA_SOURCE_URL;
/**
* @value 給靜態變量賦值,需要增加 set 方法
* 方法名稱和參數可任意。
* @param val
*/
@Value ("${spring.datasource.url}")
public void setDataSourceUrl(String val){
DATA_SOURCE_URL=val;
}
@GetMapping("val")
public String getVal(){
return "端口號="+ port+",DataSource URL="+DATA_SOURCE_URL;
}
}
復制代碼
注意@value 給靜態變量賦值的方法。
運行結果:
作者:淡若清風丶
鏈接:https://juejin.cn/post/6993137390000799752
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
示圖
啟動說明
流程圖
平臺架構
進程內郵件隊列
項目結構
├─src │ ├─main │ │ ├─java │ │ │ └─com │ │ │ └─itstyle │ │ │ └─mail │ │ │ │ Application.java │ │ │ │ │ │ │ ├─demo │ │ │ │ CountDownLatchDemo.java │ │ │ │ Ticket.java │ │ │ │ TicketRun.java │ │ │ │ │ │ │ ├─model │ │ │ │ Email.java │ │ │ │ │ │ │ ├─queue │ │ │ │ ConsumeMailQueue.java │ │ │ │ MailQueue.java │ │ │ │ │ │ │ ├─redis │ │ │ │ Receiver.java │ │ │ │ RedisConfig.java │ │ │ │ RedisListener.java │ │ │ │ │ │ │ ├─service │ │ │ │ │ IMailService.java │ │ │ │ │ │ │ │ │ └─impl │ │ │ │ MailServiceImpl.java │ │ │ │ │ │ │ ├─task │ │ │ │ SendMail.java │ │ │ │ │ │ │ └─util │ │ │ CommonUtil.java │ │ │ Constants.java │ │ │ MailUtil.java │ │ │ │ │ ├─resources │ │ │ │ application-dev.properties │ │ │ │ application-prod.properties │ │ │ │ application-test.properties │ │ │ │ application.yml │ │ │ │ spring-context-dubbo.xml │ │ │ │ spring-context-task.xml │ │ │ │ │ │ │ └─static │ │ │ ├─file │ │ │ │ 關注科幫網獲取更多源碼.zip │ │ │ │ │ │ │ ├─image │ │ │ │ springcloud.png │ │ │ │ │ │ │ └─template │ │ │ welcome.flt │ │ │ welcome.html │ │ │ │ │ └─webapp │ │ │ index.jsp │ │ │ │ │ └─WEB-INF │ │ web.xml │ │ │ └─test │ └─java │ └─com │ └─itstyle │ └─mail │ └─test │ SpringbootMailApplication.java
對比測試,建議使用Freemarker模版
application.properties中配置以下內容:
spring.mail.host=smtp.qq.com spring.mail.username=345849402@qq.com #授權碼g,在QQ郵箱客戶端生成 修改成自己的 設置-賬戶-開啟服務-獲取授權碼 spring.mail.password=XXXXXXX spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true spring.mail.properties.mail.smtp.starttls.required=true #freemarker spring.freemarker.template-loader-path=classpath:/static/template/ spring.freemarker.enabled=true spring.freemarker.cache=false spring.freemarker.charset=UTF-8 spring.freemarker.content-type=text/html spring.freemarker.allow-request-override=false spring.freemarker.check-template-location=true spring.freemarker.expose-request-attributes=false spring.freemarker.expose-session-attributes=false spring.freemarker.expose-spring-macro-helpers=false #thymeleaf spring.thymeleaf.prefix=classpath:/static/template/ spring.thymeleaf.suffix=.html spring.thymeleaf.mode=HTML5 spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.content-type=text/html spring.thymeleaf.cache=false
封裝實體
首先我們,封裝一個Email實體Email.java:
/** * Email封裝類 * 創建者 科幫網 * 創建時間 2017年7月20日 * */ public class Email implements Serializable { private static final long serialVersionUID=1L; //必填參數 private String email;//接收方郵件 private String subject;//主題 private String content;//郵件內容 //選填 private String template;//模板 private HashMap<String, String> kvMap;// 自定義參數 ... 省略 get set
業務實現
既然用了spring,就按照spring的方式來,先定義一個接口IMailService,接著是實現MailServiceImpl。
以下代碼,實現了四種方式:純文本,富文本(圖片,附件),Freemarker模版以及Thymeleaf模版。
這里需要注意的是,springboot 1.4.0以后 Velocity 廢棄了,官方建議用freemaker。而thymeleaf是博主自己實現的,顯然效率沒有freemaker高(評測對比見文章底部)。
@Service public class MailServiceImpl implements IMailService { @Autowired private JavaMailSender mailSender;//執行者 @Autowired public Configuration configuration;//freemarker @Autowired private SpringTemplateEngine templateEngine;//thymeleaf @Value("${spring.mail.username}") public String USER_NAME;//發送者 @Override public void send(Email mail) throws Exception { MailUtil mailUtil=new MailUtil(); SimpleMailMessage message=new SimpleMailMessage(); message.setFrom(USER_NAME); message.setTo(mail.getEmail()); message.setSubject(mail.getSubject()); message.setText(mail.getContent()); mailUtil.start(mailSender, message); } @Override public void sendHtml(Email mail) throws Exception { MailUtil mailUtil=new MailUtil(); MimeMessage message=mailSender.createMimeMessage(); MimeMessageHelper helper=new MimeMessageHelper(message, true); helper.setFrom(USER_NAME); helper.setTo(mail.getEmail()); helper.setSubject(mail.getSubject()); helper.setText( "<html><body><img src=\"cid:springcloud\" ></body></html>", true); // 發送圖片 File file=ResourceUtils.getFile("classpath:static" + Constants.SF_FILE_SEPARATOR + "image" + Constants.SF_FILE_SEPARATOR + "springcloud.png"); helper.addInline("springcloud", file); // 發送附件 file=ResourceUtils.getFile("classpath:static" + Constants.SF_FILE_SEPARATOR + "file" + Constants.SF_FILE_SEPARATOR + "關注科幫網獲取更多源碼.zip"); helper.addAttachment("科幫網", file); mailUtil.startHtml(mailSender, message); } @Override public void sendFreemarker(Email mail) throws Exception { MimeMessage message=mailSender.createMimeMessage(); MimeMessageHelper helper=new MimeMessageHelper(message, true); helper.setFrom(USER_NAME); helper.setTo(mail.getEmail()); helper.setSubject(mail.getSubject()); Map<String, Object> model=new HashMap<String, Object>(); model.put("content", mail.getContent()); Template template=configuration.getTemplate(mail.getTemplate()+".flt"); String text=FreeMarkerTemplateUtils.processTemplateIntoString( template, model); helper.setText(text, true); mailSender.send(message); } @Override public void sendThymeleaf(Email mail) throws Exception { MimeMessage message=mailSender.createMimeMessage(); MimeMessageHelper helper=new MimeMessageHelper(message, true); helper.setFrom(USER_NAME); helper.setTo(mail.getEmail()); helper.setSubject(mail.getSubject()); Context context=new Context(); context.setVariable("email", mail); String text=templateEngine.process(mail.getTemplate(), context); helper.setText(text, true); mailSender.send(message); } }
測試用例
老司機帶你去開車SpringbootMailApplication.java:
*請認真填寫需求信息,我們會在24小時內與您取得聯系。