这是一个课程项目,由于临近期末,匆忙写了,但是没有在做总结,现在总的做一下总结
用到的技术:
- SpringBoot
- Mybatis
- Quartiz
- FreeMarker
- 邮件发送用的Springboot自带的
项目在线地址: http://todo.nwuer.com
Github地址: https://github.com/vividzcs/PowerYourself
- 依赖介绍
- Springboot集成Mybatis
- Springboot集成Quartz
- 在Springboot中使用freemarker
依赖介绍
没加注释的都是创建springboot时可以勾选的
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--用于quartz将任务持久化到数据库的数据库连接池-->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- mappers pager -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>com.github.miemiedev</groupId>
<artifactId>mybatis-paginator</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>0.9.4</version>
</dependency>
<!--guava缓存-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
<!--web程序监视器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--切面-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!--JSR-303规范 Bean验证工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--get set 构造方法 toString logger 自动生成工具-->
<!--注意:需要IDE也安装对应插件,可直接在plugins里面搜,不安装,语法报错但不影响编译和运行-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
Springboot集成Mybatis
- mybatis基础配置
- 使用mybatis-generator逆向生成代码
mybatis基础配置
mybatis.mapper-locations=classpath:mappers/*.xml #SQL语句的配置文件
mybatis.type-aliases-package=com.nwuer.core.entity # 实体类存放的包
mybatis.configuration.map-underscore-to-camel-case=true #开启驼峰转换,这样数据库中的 user_id会转换成springboot程序里的userId
经过上面的配置,只需在com.nwuer.dao下创建UserDao接口
然后注解上@Mapper
Mybatis就可以通过Springboot创建对象的代理是实现类,完成对应的Sql操作
如果不了解Mybatis应该先去了解下Mybatis再看这篇文章
例如:
- classpath:mappers/CategoryMapper.xml
<?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.nwuer.core.dao.CategoryMapper" >
<delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
delete from category
where id = #{id,jdbcType=CHAR}
</delete>
</mapper>
- com.nwuer.dao下
@Mapper
public interface CategoryMapper {
int deleteByPrimaryKey(String id);
}
使用mybatis-generator逆向生成代码
- pom.xml中插件的配置
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.2</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
<configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
</dependencies>
</plugin>
- 创建一个datasource.properties存储数据库驱动jar的位置和相关连接信息
db.driverLocation=E:/ProgramData/repository/mysql/mysql-connector-java/5.1.46/mysql-connector-java-5.1.46.jar # 你本机jar包的位置
db.driverClassName=com.mysql.jdbc.Driver
db.url=jdbc:mysql://ip:3306/poweryourself?useUnicode=true&characterEncoding=utf-8 # 连接字符串
db.username=poweryourself
db.password=password
- 创建generatorConfig.xml
一个问题是当你用插件生成XxxMapper.xml后,再次生成时候,会在XxxMapper追加相同的自动生成的代码,这样会出错
还没找到解决办法
所以我们如果想第二次使用这个插件生成
可以先备份xml文件,然后删除包下的,然后自动生成,再将后来添加的复制进去
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--导入属性配置-->
<properties resource="datasource.properties"></properties>
<!--指定特定数据库的jdbc驱动jar包的位置-->
<classPathEntry location="${db.driverLocation}"/>
<context id="default" targetRuntime="MyBatis3">
<property name="mergeable" value="false"></property>
<!-- optional,旨在创建class时,对注释进行控制 -->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--jdbc的数据库连接 -->
<jdbcConnection
driverClass="${db.driverClassName}"
connectionURL="${db.url}"
userId="${db.username}"
password="${db.password}">
</jdbcConnection>
<!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类
targetPackage 指定生成的model生成所在的包名
targetProject 指定在该项目下所在的路径
-->
<javaModelGenerator targetPackage="com.nwuer.core.entity" targetProject="./src/main/java">
<!-- 是否允许子包,即targetPackage.schemaName.tableName -->
<property name="enableSubPackages" value="false"/>
<!-- 是否对model添加 构造函数 -->
<property name="constructorBased" value="true"/>
<!-- 是否对类CHAR类型的列的数据进行trim操作 -->
<property name="trimStrings" value="true"/>
<!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
<property name="immutable" value="false"/>
</javaModelGenerator>
<!--mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 -->
<!--<sqlMapGenerator targetPackage="mappers" targetProject=".\src\main\resources">-->
<sqlMapGenerator targetPackage="mappers" targetProject="./src/main/resources">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口
-->
<!-- targetPackage:mapper接口dao生成的位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.nwuer.core.dao" targetProject="./src/main/java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!--<table tableName="user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
<columnOverride column="last_login_datetime" javaType="java.time.LocalDateTime"></columnOverride>
</table>-->
<!--<table tableName="category" domainObjectName="Category" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>-->
<table tableName="task" domainObjectName="Task" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>
<!-- mybatis插件的搭建 -->
</context>
</generatorConfiguration>
Springboot集成Quartz
之前介绍依赖的时候就已经添加过c3p0连接池
这里配置的持久化就是用的c3p0连接池
本来查也是可以用quartz提供的,但是项目中为了方便,自由的查信息,自己用mybatis查的quartz相关表(不过是多余的,项目没用上)
-
quartz持久化时用到的相关表在官网下的压缩包有提供,我们这用的红框中的
在resources下创建quartz.properties
# 固定前缀org.quartz
# 主要分为scheduler、threadPool、jobStore、plugin等部分
#
#
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount = 5
# 优先级
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
org.quartz.jobStore.misfireThreshold = 5000
# 默认存储在内存中
#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.useProperties=false
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = qzDS
org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.qzDS.URL = jdbc:mysql://ip/poweryourself?useUnicode=true&characterEncoding=utf-8
org.quartz.dataSource.qzDS.user = poweryourself
org.quartz.dataSource.qzDS.password = 密码
org.quartz.dataSource.qzDS.maxConnections = 10
- 在springboot中使用quartz(更简单的做法参考,springboot集成的:http://www.baeldung.com/spring-quartz-schedule)
Scheduler代表一个调度容器,一个调度容器可以注册多个JobDetail和Trigger.当Trigger和JobDetail组合,就可以被Scheduler容器调度了
JobDetail 表示一个具体的可执行的调度程序,job是这个可执行调度程序所要执行的内容
Trigger代表一个调度参数的配置,什么时候去调度
使用quartz只需4步
- com.nwuer.core.configuration.SchedulerConfig 用于读取quartz配置文件
1.1. 这里还做了一步,不然下面的JobAndTriggerServiceImpl将不能用于注入
为了在JOB中使用Spring管理的Bean,需要重新定义一个Job Factory- com.nwuer.core.pojo.PowerYourselfJob 一个任务(这里是发送邮件),在这个里面做具体的事情
- com.nwuer.core.service.impl.JobAndTriggerServiceImpl 使用SchedulerConfig中注入springboot容器的Scheduler对象来实现任务的增删改查(具体去Github上看)
- com.nwuer.core.configuration.SchedulerConfig
package com.nwuer.core.configuration;
import org.quartz.Scheduler;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.io.IOException;
import java.util.Properties;
/**
* 对quartz.rpoperties进行读取
* @author vividzc
*
*/
@Configuration
public class SchedulerConfig {
@Autowired
private MyJobFactory myJobFactory;
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setOverwriteExistingJobs(true);
// 延时启动
factory.setStartupDelay(20);
// 加载quartz数据源配置
factory.setQuartzProperties(quartzProperties());
// 自定义Job Factory,用于Spring注入
factory.setJobFactory(myJobFactory);
return factory;
}
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
//在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
/*
* quartz初始化监听器
*/
@Bean
public QuartzInitializerListener executorListener() {
return new QuartzInitializerListener();
}
/*
* 通过SchedulerFactoryBean获取Scheduler的实例
*/
@Bean(name="scheduler")
public Scheduler scheduler() throws Exception {
return schedulerFactoryBean().getScheduler();
}
}
- com.nwuer.core.configuration.MyJobFactory
package com.nwuer.core.configuration;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
@Component
public class MyJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
- com.nwuer.core.pojo.PowerYourselfJob
package com.nwuer.core.pojo;
import com.nwuer.core.common.Const;
import com.nwuer.core.common.util.DateParseForCronExpressionUtil;
import com.nwuer.core.common.util.TokenCache;
import com.nwuer.core.dto.JobDto;
import com.nwuer.core.dto.UserDto;
import com.nwuer.core.service.MailSendService;
import com.nwuer.core.service.impl.JobService;
import com.nwuer.core.service.impl.UserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Job: 表示一个任务,要执行的具体内容
* @author vividzc
* @date 2018/6/14 23:03
*/
@Slf4j
@Component
public class PowerYourselfJob extends BaseJob {
@Autowired
private UserServiceImpl userService;
@Autowired
private JobService jobService;
@Autowired
private MailSendService mailSendService;
@Override
public void execute(JobExecutionContext context) {
log.info("PowerYouself执行:"+new Date().toString());
JobDetail jobDetail = context.getJobDetail();
String jobName = jobDetail.getKey().getName();
String userId = jobDetail.getKey().getGroup();
//得到UserDto
UserDto userDto = userService.selectById(userId);
//得到任务信息
JobDto jobDto = jobService.selectById(jobName);
//发送邮件
Map<String,String> map = new HashMap<>();
map.put("title",jobDto.getTitle());
map.put("beganTime", DateParseForCronExpressionUtil.getDateString(jobDto.getBeganTime()));
map.put("endTime",DateParseForCronExpressionUtil.getDateString(jobDto.getEndTime()));
map.put("remindTime",DateParseForCronExpressionUtil.getDateString(jobDto.getRemindTime()));
map.put("desc",jobDto.getNotation());
map.put("domain",Const.URL_PREFIX);
map.put("done_url", Const.URL_PREFIX+"/user/job/done/"+jobName);
map.put("delete_url", Const.URL_PREFIX+"/user/job/delete/"+jobName);
map.put("job_id",jobName);
map.put("user_id",userId);
TokenCache.setKey(Const.JOB_TOKEN_PREFIX+jobName,jobName);
mailSendService.sendEmail(userDto.getEmail(),map);
}
}
- com.nwuer.core.service.impl.JobAndTriggerServiceImpl
package com.nwuer.core.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.nwuer.core.common.ResponseCode;
import com.nwuer.core.common.exception.PowerYourselfException;
import com.nwuer.core.dao.JobAndTriggerMapper;
import com.nwuer.core.entity.JobAndTrigger;
import com.nwuer.core.pojo.BaseJob;
import com.nwuer.core.service.IJobAndTriggerService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author vividzc
* @date 2018/6/14 23:18
*/
@Slf4j
@Service
public class JobAndTriggerServiceImpl implements IJobAndTriggerService {
private final JobAndTriggerMapper jobAndTriggerMapper;
/**
* Scheduler代表一个调度容器,一个调度容器可以注册多个JobDetail和Trigger.当Trigger和JobDetail组合,就可以被Scheduler容器调度了
*/
private final Scheduler scheduler;
@Autowired
public JobAndTriggerServiceImpl(JobAndTriggerMapper jobAndTriggerMapper,Scheduler scheduler){
this.jobAndTriggerMapper = jobAndTriggerMapper;
this.scheduler = scheduler;
}
@Override
public PageInfo<JobAndTrigger> queryJob(int pageNum, int pageSize) {
PageHelper.startPage(pageNum, pageSize);
List<JobAndTrigger> list = jobAndTriggerMapper.getJobAndTriggerDetails();
PageInfo<JobAndTrigger> page = new PageInfo<JobAndTrigger>(list);
return page;
}
/**
* 添加一个任务
* @param job
* @throws SchedulerException
*/
public void addJob(BaseJob job) throws SchedulerException {
/** 创建JobDetail实例,绑定Job实现类
* JobDetail 表示一个具体的可执行的调度程序,job是这个可执行调度程序所要执行的内容
* 另外JobDetail还包含了这个任务调度的方案和策略**/
// 指明job的名称,所在组的名称,以及绑定job类
JobDetail jobDetail = JobBuilder.newJob(job.getBeanClass())
.withIdentity(job.getJobKey())
.withDescription(job.getDescription())
.usingJobData(job.getDataMap())
.build();
/**
* Trigger代表一个调度参数的配置,什么时候去调度
*/
//定义调度触发规则, 使用cronTrigger规则
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(job.getJobName(),job.getJobGroup())
.withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression()))
.startNow()
.build();
//将任务和触发器注册到任务调度中去
scheduler.scheduleJob(jobDetail,trigger);
//判断调度器是否启动
if(!scheduler.isStarted()){
scheduler.start();
}
log.info(String.format("定时任务:%s.%s-已添加到调度器!", job.getJobGroup(),job.getJobName()));
}
/**
* 根据任务名和任务组名来暂停一个任务
* @param jobName
* @param jobGroupName
* @throws SchedulerException
*/
public void pauseJob(String jobName,String jobGroupName) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(jobName,jobGroupName));
}
/**
* 根据任务名和任务组名来恢复一个任务
* @param jobName
* @param jobGroupName
* @throws SchedulerException
*/
public void resumeJob(String jobName,String jobGroupName) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(jobName,jobGroupName));
}
public void rescheduleJob(String jobName,String jobGroupName,String cronExpression,String description) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withDescription(description).withSchedule(scheduleBuilder).build();
if(trigger == null){
throw new PowerYourselfException(ResponseCode.JOB_HAS_REMINDED);
}
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
/**
* 根据任务名和任务组名来删除一个任务
* @param jobName
* @param jobGroupName
* @throws SchedulerException
*/
public void deleteJob(String jobName,String jobGroupName) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName,jobGroupName);
scheduler.pauseTrigger(triggerKey); //先暂停
scheduler.unscheduleJob(triggerKey); //取消调度
boolean flag = scheduler.deleteJob(JobKey.jobKey(jobName,jobGroupName)); //删除任务
}
}
使用Springboot自带的邮件发送
由于这个很简单,便只做简单介绍
- 注入springboot为我们实现的JavaMailSender
- 构造邮件
- 使用JavaMailSender发送邮件
com.nwuer.core.service.impl.SendSimpleEmailService
package com.nwuer.core.service.impl;
import com.nwuer.core.common.Const;
import com.nwuer.core.dto.UserDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import javax.mail.MessagingException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.UnsupportedEncodingException;
/**
* @author vividzc
* @date 2018/6/25 19:25
*/
@Service
public class SendSimpleEmailService {
/**
* mailSender注入
* 1. 注入springboot为我们实现的JavaMailSender
*/
private final JavaMailSender mailSender;
/**
* 发件人邮箱
*/
@Value("${spring.mail.username}")
private String senderEmail;
/**
* app名字
*/
@Value("${nwuer.app.brand}")
private String brand;
@Autowired
public SendSimpleEmailService( JavaMailSender mailSender) {
this.mailSender = mailSender;
}
/**
* 发送邮件
*/
public void sendEmail(UserDto userDto,String url) throws MessagingException, UnsupportedEncodingException {
String token = Const.TOKEN_PREFIX + userDto.getId();
//构造邮件
String subject = "您在" + brand + "重置密码,请继续操作!";
String resetUrl
= url + "/reset?token=" + token;
String message = "<h2>点击链接,重置您的密码为:"+Const.INITAIL_PASSWORD+"</h2><br/><p>如果被阻拦可以复制链接到新窗口打开(12小时后失效)</p><br/>";
/////////////////////////
// 2. 构造邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
InternetAddress from = new InternetAddress();
from.setAddress(senderEmail);
from.setPersonal(brand, "UTF-8");
helper.setFrom(from);
helper.setTo(userDto.getEmail());
helper.setSubject(subject);
StringBuilder sb = new StringBuilder(message);
sb.append("<br/>");
sb.append(brand);
sb.append(":<br/>重置密码: " + resetUrl);
helper.setText(sb.toString(), true);
//3.使用JavaMailSender发送邮件
mailSender.send(mimeMessage);
}
}
在Springboot中使用freemarker
听说springboot是推荐使用freemarker或Thymeleaf(不推荐jsp)
而且就算你不配置也可以直接使用(本项目便在开发环境配置了,在生产环境没有配置,结果并没有影响,不过如果你想自定义,就可以在application.properties中配置)
- 部分配置:application.properties(可选)
# FreeeMarker 模板引擎配置 关闭freemarker缓存
spring.freemarker.allow-request-override=false
spring.freemarker.cache=false
spring.freemarker.check-template-location=true
spring.freemarker.charset=UTF-8
spring.freemarker.content-type=text/html
spring.freemarker.expose-request-attributes=false
spring.freemarker.expose-session-attributes=false
spring.freemarker.expose-spring-macro-helpers=false
篇幅已经很长了,这个项目虽然小,但是作为一个小项目来练手还是很不错的,里面也涉及了很多的东西,可以去我的Github(https://github.com/vividzcs/PowerYourself)去看看,之后有时间再整理出单个的知识点,这里先写到这里,有问题欢迎指出.
参考文献: