文章目录
代码在 https://github.com/betterGa/SpringBootDemo
一、Spring Boot Thymeleaf 示例
概述
Thymeleaf 是一个基于 Java 的库,用于创建 Web 应用程序, 它为在Web 应用程序中提供 XHTML/HTML5 提供了很好的支持。
Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP ,相较与其他的模板引擎,它有如下三个吸引人的特点:
(1)Thymeleaf 在 有网络 和 无网络 的环境下皆可运行,即 它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板 + 数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
(2)Thymeleaf 开箱即用的特性,它提供标准和 Spring 标准两种方言,可以直接套用模板实现 JSTL、OGNL 表达式效果,避免每天套模板、改 JSTL、改标签的困扰,同时开发人员也可以扩展和创建自定义的方言。
(3)Thymeleaf 提供 Spring 标准方言和一个与 SpringMVC 完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
引入 thymeleaf 依赖
- pom 文件中加入以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
创建 thymeleaf 模板
在 resoures 包下新建 templates下包,新建 index.html :
<!doctype html> <!--注意:引入thymeleaf的名称空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title></head>
<body><p th:text="hello">Hello</p></body>
</html>
提供控制类:
@Controller
public class indexController {
@RequestMapping("/index")
public String index(){
// 默认找 temple.index.html 这个模板视图文件
return "index";
}
}
运行结果:
通过控制器定位 thymeleaf 模板
接下来看看 thymeleaf 常用标签的使用。
首先,提供一个实体类:
public class User {
private String userName;
private String password;
private List<String> hobbies;
private HashMap<String,String> secrets;
}
控制类:
@Controller
public class indexController {
@RequestMapping("/index")
public String index(Model model){
User user= new User();
user.setUserName("jia");
user.setPassword("123456");
user.setHobbies(Arrays.asList(new String[]{
"football","singing","dance"}));
HashMap<String,String> map=new HashMap();
map.put("1","a");
map.put("2","b");
map.put("3","c");
map.put("4","d");
user.setSecrets(map);
model.addAttribute("user",user);
// 默认找 temple.index.html 这个模板视图文件
return "index";
}
}
然后在 index.html 中 显示 user 对象:
<p th:text="${user}"></p>
这里 ${user} 的 “user 和 :model.addAttribute("user",user);
里的第一个 “user” 是对应的。运行结果:
接下来依次获取属性,可以直接获取属性,也可以通过 getter 方法:
<p th:text="${user}"></p>
<p th:text="${user.getUserName()}"></p>
<p th:text="${user.getPassword()}"></p>
<p th:text="${user.hobbies}"></p>
<p th:text="${user.secrets}"></p>
<table th:each="item,sta:${user.hobbies}">
<tr>
<td th:text="${item}"></td>
<td th:text="${sta.index}"></td>
<td th:text="${sta.odd}"></td>
<td th:text="${sta.size}"></td>
</tr>
</table>
<div th:each="item:${user.secrets}" th:text="${item.key}"></div>
<div th:each="item:${user.secrets}" th:text="${item.value}"></div>
<input type="text" th:attr="value=${user.userName}">
<input type="text" th:attr="value=${user.password}">
运行结果:
二、SpringBoot 使用 RESTful 服务
提供商品实体类:
public class Products {
private String name;
private String id;
}
提供两个控制类,它们 会默认找 template 包里的 html ( thymeleaf 模板 的使用就是这样的,控制类上加 @Controller 注解,返回的就是 template 包里对应的 html ):
@Controller
public class ProductController {
static List<Products> list = new ArrayList<>();
static {
list.add(new Products("1", "衣服"));
list.add(new Products("2", "鞋子"));
list.add(new Products("3", "帽子"));
}
// 查询
@RequestMapping("/view-products")
public String viewProducts() {
return "view-product";
}
// 新增
@RequestMapping("/add-products")
public String addProducts() {
return "add-product";
}
// 获取商品列表
@GetMapping("/products")
@ResponseBody
public List<Products> getProducts(){
return list;
}
@PostMapping("/products")
@ResponseBody
public Products addProducts(@RequestBody Products products){
list.add(products);
return products;
}
接下来提供对应的 html,添加 jQuery 库并 编写代码,在页面加载时使用 RESTful Web服务,先写 view-products.html :
<html xmlns="http://www.w3.org/1999/html">
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
<script> $(document).ready(function () {
$.getJSON("http://localhost:9999/products", function (result) {
$.each(result, function (key, value) {
$("#productsJson").append(value.id + " " + value.name + " ");
});
});
});
</script>
</head>
<bodyb
<div id="productsJson"></div>
</body>
</html>
运行结果:
再写 add-products.html :
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
<script>
$(document).ready(function () {
$("button").click(function () {
var newProduct = {
id: "4", name: "车子"};
var productstr = JSON.stringify(newProduct);
$.ajax({
type: "POST",
url: "http://localhost:9999/products",
contentType: "application/json;charset=UTF-8",
data: productstr,
success: function (data) {
alert("新增" + data.name + "成功!");
},
error: function (data) {
alert(data);
}
}
);
});
});
</script>
</head>
<body>
<button>新增商品</button>
</body>
</html>
运行结果:
三、Spring Boot 国际化
国际化 是一个 使应用程序适应不同语言和区域 而 无需对源代码进行工程更改的过程。就是说,根据不同的国家展示不同的语言。
默认情况下,Spring Boot 应用程序从 类路径下的 src/main/resources 文件夹中获取 消息源。 缺省语言环境消息文件名应为 message.properties ,每个语言环境的文件应命名为 messages_XX.properties 。 “XX”表示区域代码。 (注意喔,是 messages ,达成 message 都是访问不到的!)应将所有消息属性设置为键值对。 如果在语言环境中找不到任何属性,则应用程序将使用 messages.properties 文件中的默认属性。
比如,英文,messages.properties :
welcome.text = welcome everyone
中文,messages_cn.properties :
welcome.text = 欢迎大家
提供访问路径:
@RequestMapping("/locale")
public String locale(){
return "locale";
}
提供相应的 locale.html 页面:
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>springboot国际化</title>
</head>
<body>
<h1 th:text="#{welcome.text}">
</h1>
</h1>
</body>
</html>
需要确定应用程序的默认 Locale,添加 LocaleResolver bean :
@Bean
public LocaleResolver localeResolver(){
SessionLocaleResolver sessionLocaleResolver=new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(Locale.US);
return sessionLocaleResolver;
}
需要拦截器 用于 根据 添加到请求的语言参数的值 更改新的 Locale,在 InterceptorConfig 类中新增方法:
@Bean
public LocaleChangeInterceptor localeChangeInterceptor(){
LocaleChangeInterceptor localeChangeInterceptor=new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("language");
return localeChangeInterceptor;
}
然后注册这个拦截器:
运行结果:
将参数 language=cn 传入:
(如果中文出现了乱码,注意把 IDEA 项目字符编码为 UTF-8 :
)
四、Spring Boot 启动 Swagger3
Swagger3 是一个开源项目,用于为 RESTful Web 服务生成 REST API 文档,文档里会描述接口的信息,比如它的功能、参数、返回值等等。 它提供了一个用户界面,可通过 Web 浏览器访问 RESTful Web 服务。
要在Spring Boot应用程序中启用Swagger3,需要在 pom.xml 中添加以下依赖项:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
接下来,在 主Spring Boot应用程序中 添加 @EnableOpenApi 注释。 @EnableOpenApi 注释用于为Spring Boot应用程序启用 Swagger3:
控制类方法上
其他方法也是同理,在方法上加 @ApiOperation 注解,并写入方法的作用即可。
实体类上使用 @ApiModel 注解,属性使用 @ApiModelProperty :
运行结果:
接下来,进行一些配置,比如说只显示我们注释了的类,需要创建 Docket Bean 以为 Spring Boot 应用程序配置 Swagger3 :
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("Swagger3 接口文档")
.description("描述")
.contact(new Contact("jia","http://www.jia.com","[email protected]"))
.version("1.0")
.build();
}
这时再运行:
五、Spring Boot 发送电子邮件
通过使用 Spring Boot RESTful Web 服务,可以发送包含 pop/stml 传输层安全性的电子邮件。
首先,在 pom.xml 中添加 Spring Boot Starter Mail 依赖项。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
接下来,需要打开邮箱的 POP3/SMTP服务,开启后会给出一串授权码,需要拷贝保存下来:
:
如果只是发送简单邮件(没有附件),则只需要在 application.properties 文件中配置
spring.mail.default-encoding=UTF-8
spring.mail.host=smtp.163.com
[email protected]
##注意这个配置是设置邮件接收配置后给的授权码,不是邮箱密码
spring.mail.password=QSTSIXQQLJUIGWQV
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
提供控制类:
package com.jia.SpringBootDemo.controller;
@RestController
public class EmailController {
@Autowired
JavaMailSender javaMailSender;
@RequestMapping("/sendMail")
public String sendMail(){
mail();
return "发送成功";
}
public void mail(){
// 发送简单邮件,无附件
SimpleMailMessage message=new SimpleMailMessage();
message.setFrom("[email protected]");
message.setSubject("邀请函");
message.setText("发来一封邀请函");
message.setTo("[email protected]");
javaMailSender.send(message);
}
}
运行结果:
而且可以看到,确实是发送、接受到了邮件。
接下来发送带附件的邮件:
// 复杂邮件 = 正文 + 附件
private void mail1() throws MessagingException, IOException {
// 设置邮件服务器的属性
Properties properties=new Properties();
properties.put("mail.host","smtp.163.com");
properties.put("mail.transport.protocol","smtp");
properties.put("mail.smtp.auth","true");
properties.put("mail.smtp.socketFactory.class","javax.net.ssl.SSLSocketFactory");
properties.put("mail.smtp.port","465");
Session session=Session.getDefaultInstance(properties);
MimeMessage mimeMessage = new MimeMessage(session);
// 设置邮件来源
mimeMessage.setFrom(new InternetAddress("[email protected]",false));
// 设置邮件接收方
mimeMessage.setRecipients(Message.RecipientType.TO, InternetAddress.parse("[email protected]"));
// 设置邮件主题
mimeMessage.setSubject("一封邮件");
// 设置邮件日期
mimeMessage.setSentDate(new Date());
// 正文部分
MimeBodyPart mimeBodyPart = new MimeBodyPart();
mimeBodyPart.setText("发来一封邀请函,带附件");
// 附件部分
MimeBodyPart attachPart = new MimeBodyPart();
attachPart.attachFile("D:/pictures/pickGirl.jpg");
// 消息载体
MimeMultipart mimeMultipart = new MimeMultipart();
mimeMultipart.addBodyPart(mimeBodyPart);
mimeMultipart.addBodyPart(attachPart);
// 将消息载体作为整个邮件的主体内容
mimeMessage.setContent(mimeMultipart);
Transport transport=session.getTransport();
// 连接发送端
transport.connect("smtp.163.com","[email protected]","QSTSIXQQLJUIGWQV");
transport.sendMessage(mimeMessage,mimeMessage.getAllRecipients());
transport.close();
}
六、Spring Boot 批量处理
批处理服务是 在单个任务中执行多个命令的过程,
Spring Batch 是 处理大量数据操作的一个框架,主要用来读取大量数据,然后进行一定的处理后输出指定的形式。比如我们可以将 csv 文件中的数据(数据量几百万甚至几千万都是没问题的)批处理插入保存到数据库中 ,就可以使用该框架。
-
Spring Batch 框架的组成部分
(1)JobRepository:用来注册 Job 容器,设置数据库相关属性。
(2)JobLauncher:用来启动 Job 的接口。
(3)Job:我们要实际执行的任务,包含一个或多个。
(4)Step:即步骤,包括:ItemReader->ItemProcessor->ItemWriter。
(5)ItemReader:用来读取数据,做实体类与数据字段之间的映射。比如读取 csv 文件中的人员数据,之后对应实体 person 的字段做 mapper 。
(6)ItemProcessor:用来处理数据的接口,同时可以做数据校验(设置校验器,使用 JSR-303(hibernate-validator) 注解),比如将中文性别 男/女,转为 M/F。同时校验年龄字段是否符合要求等 。
(7)ItemWriter:用来输出数据的接口,设置数据库源。编写预处理 SQL 插入语句。
-
批处理流程图
- 实战
首先,添加依赖:
<!-- spring批量处理-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<!-- 实体验证-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.7.Final</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<!--连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
接下来,在 resources 包下添加简单的 csv 文件:
建一个表 person :
CREATE TABLE `person`
( `id` int(11) NOT NULL,
`name` varchar(10) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`gender` varchar(2) NOT NULL,
PRIMARY KEY (`id`) ) ENGINE=InnoDB;
然后需要一个对应的实体类 :
public class personEntry {
private int id;
@Size(min = 2, max = 5)
private String age;
private String name;
private String gender;
/*省略构造方法、getter、setter 方法*/
提供 ItemReader 读取数据:
@Configuration
public class BatchConfig {
@Bean
public ItemReader<personEntry> reader() {
// new 一个文件阅读器
FlatFileItemReader<personEntry> reader = new FlatFileItemReader<>();
// 设置文件
reader.setResource(new ClassPathResource("person.csv"));
// 文件与实体类映射
// 设置 key
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setNames(new String[]{
"id", "name", "age", "gender"});
// 设置实体对应
BeanWrapperFieldSetMapper fieldSetMapper = new BeanWrapperFieldSetMapper<personEntry>();
fieldSetMapper.setTargetType(personEntry.class);
DefaultLineMapper<personEntry> personDefaultLineMapper = new DefaultLineMapper<personEntry>();
personDefaultLineMapper.setLineTokenizer(lineTokenizer);
personDefaultLineMapper.setFieldSetMapper(fieldSetMapper);
// 关联到阅读器
reader.setLineMapper(personDefaultLineMapper);
return reader;
}
}
提供 ItemProcessor,进行 校验和处理 ,将中文性别 男/女,转为 M/F。:
// 处理和校验数据
public class csvItemProcesser extends ValidatingItemProcessor<personEntry> {
Logger logger= LoggerFactory.getLogger(csvItemProcesser.class);
@Override
public personEntry process(personEntry item) throws ValidationException {
// 将 男/女 换成 M/F
logger.info("process is validating......");
// 在超类中进行校验
super.process(item);
// 进行处理
if(item.getGender().equals("男")) {
item.setGender("M");
} else {
item.setGender("F");
}
logger.info("process end validating......");
return item;
}
}
另外,注意到 personEntry 实体类中,使用注解 对年龄的长度进行了限制,校验年龄字段是否符合要求。✨ 注意 ,@ Size 只能用在 CharSequence 也就是 字符、字符串;Collection、Map 也就是集合;还有 Array 数组上,表示它们的 个数,不能用在数值类型上,不是进行范围校验 ✨:
@Size(min = 2, max = 5)
private String age;
接下来需要对应地定义校验器:因为 @Size 是使用 JSR-303(hibernate-validator) 注解,来校验 ItemReader 读取到的数据是否满足要求,如不满足则不会进行接下来的批处理任务:
import org.springframework.batch.item.validator.Validator;
import org.springframework.beans.factory.InitializingBean;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.ValidationException;
import javax.validation.ValidatorFactory;
import java.util.Set;
public class BeanValidator<T> implements Validator<T>, InitializingBean {
javax.validation.Validator validator;
@Override
public void validate(T t) {
Set<ConstraintViolation<T>> constraintViolationSet = validator.validate(t);
if (constraintViolationSet.size() > 0) {
StringBuilder message = new StringBuilder();
for (ConstraintViolation<T> constraintViolationSets : constraintViolationSet) {
message.append(constraintViolationSets.getMessage() + "\n");
}
throw new ValidationException(message.toString());
}
}
@Override
public void afterPropertiesSet() throws Exception {
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
validator = validatorFactory.usingContext().getValidator();
}
}
有了校验和处理数据的处理器,接下来需要在配置类 BatchConfig 中提供方法,把这俩处理器配置进来:
// 处理数据
@Bean
public ItemProcessor<personEntry,personEntry> processor(){
csvItemProcesser csvItemProcesser= new csvItemProcesser();
csvItemProcesser.setValidator(beanValidator());
return csvItemProcesser;
}
@Bean
public BeanValidator beanValidator(){
return new BeanValidator();
}
提供 ItemWritter:
@Bean
public ItemWriter<personEntry> writer(DataSource dataSource){
JdbcBatchItemWriter writer= new JdbcBatchItemWriter<>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<personEntry>());
String sql="insert into person values(:id,:name,:age,:gender)";
writer.setSql(sql);
writer.setDataSource(dataSource);
return writer;
}
注册 Job 容器:
@Bean
public JobRepository cvsJobRepository(DataSource dataSource, PlatformTransactionManager manager) throws Exception {
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
jobRepositoryFactoryBean.setDatabaseType("mysql");
jobRepositoryFactoryBean.setTransactionManager(manager);
jobRepositoryFactoryBean.setDataSource(dataSource);
return jobRepositoryFactoryBean.getObject();
}
有了 Job 容器,接下来就需要提供启动 Job 容器的接口:
// 容器启动器
@Bean
public SimpleJobLauncher csvJobLauncher(DataSource dataSource, PlatformTransactionManager manager) throws Exception {
SimpleJobLauncher simpleJobLauncher= new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(cvsJobRepository(dataSource,manager));
return simpleJobLauncher;
}
提供监视器:
// 监听器
public class JobListener implements JobExecutionListener {
Logger logger = LoggerFactory.getLogger(JobListener.class);
long startTime;
long endTime;
@Override
public void beforeJob(JobExecution jobExecution) {
startTime = System.currentTimeMillis();
logger.info("job process strat......");
}
@Override
public void afterJob(JobExecution jobExecution) {
endTime = System.currentTimeMillis();
logger.info("job process end......");
logger.info("cost time:"+(endTime-startTime)+" ms");
}
}
这样,ItemReader、ItemProcessor、ItemWritter 都有了,接下来需要定制 step :
@Bean
public Step step(StepBuilderFactory stepBuilderFactory, ItemReader<personEntry> reader,
ItemWriter<personEntry> writer, ItemProcessor<personEntry, personEntry> processor) {
return stepBuilderFactory.get("step")
// 数据是按块处理的,chunk 的机制是
// 每次拿一条数据,积累到 65000 再一次性提交给数据库
.<personEntry,personEntry>chunk(65000)
.reader(reader)
.processor(processor)
.writer(writer)
.build();
}
这时需要给 BatchConfig 类上添加 @EnableBatchProcessing 注解,开启批量处理器:
还需要 @Import(DruidDBConfig.class) 注解,导入数据源的相关配置,配置写在 DruidDBConfig 类中:
// 数据库配置
@Configuration
public class DruidDBConfig {
private Logger logger = LoggerFactory.getLogger(DruidDBConfig.class);
@Value("${spring.datasource.url}")
private String dbUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Bean
@Primary
// 被注入的优先级最高
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
logger.info("-------->dataSource[url=" + dbUrl + " ,username=" + username + "]");
dataSource.setUrl(dbUrl);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driverClassName);
return (DataSource) dataSource;
}
@Bean
public ServletRegistrationBean druidServletRegistrationBean() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.addUrlMappings("/druid/*");
return servletRegistrationBean;
}
/*** 注册DruidFilter拦截 ** @return */
@Bean
public FilterRegistrationBean duridFilterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
Map<String, String> initParams = new HashMap<String, String>(); //设置忽略请求 initParams.put("exclusions", "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*");
filterRegistrationBean.setInitParameters(initParams);
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
相应的,需要在 application.yml 中配置数据源的相应信息 和 batch 信息:
##数据源配置
##数据源配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.1.109:3306/SpringBatch?useSSL=false&serverTimezone=UTC&characterEncoding=utf8&allowPublicKeyRetrieval=true
password: jia
username: root
batch:
job:
# 默认自动执行定义的 job(true),该为 false,需要 jobLaucher.run 执行
enable: false
initialize-schema: always
提供 JobController 类:
@RestController
public class JobController {
@Autowired
SimpleJobLauncher simpleJobLauncher;
@Autowired
Job importJob
@RequestMapping("/startJob")
public void startJob() throws JobParametersInvalidException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
JobParameters jobParametERS = new JobParametersBuilder().addLong("time", System.currentTimeMillis())
.toJobParameters();
simpleJobLauncher.run(importJob, jobParametERS);
}
}
启动项目,发现报了个错:
可以看到,出现了 jar 包冲突 ,多个 jar 包 中包含同一个类。解决思路:将 The method’s class, javax.servlet.ServletContext, is available from the following locations: 提示的 jar 删除。
又报错,
主要问题是 java.sql.SQLException: null, message from server: “Host ‘LAPTOP-FDS94CNE’ is not allowed to connect to this MySQL server” ,遇到这样的问题,需要到数据库中把 host 名换成 IP 地址:
运行结果:
这时在 person.csv 中新增一条 6,jia,1,女
,再运行程序,会看到报错:
可以看到,是进行了 age 的长度验证的。
七、总结
(1)在 Spring Boot 中集成 thymeleaf 后,在 resources/template 包中提供 html,
就可以在控制类中访问到 命名相同的模板视图文件。
(2)Spring Boot 应用程序会从 类路径下的 src/main/resources 文件夹中获取 消息源,来适配语言, 默认的消息文件名为 message.properties ,每个语言环境的文件应命名为 messages_XX.properties 。 “XX”表示区域代码。
(3) Spring Boot应用程序中 @EnableOpenApi 注释用于启用 Swagger3,用于启动类上。控制类上用 @Api 注解,其方法用 @ApiOperation 注解,实体类上用 @ApiModel 注解,属性使用 @ApiModelProperty 注解。
(4)发送电子邮件需要发送方的邮箱授权,无附件的邮件使用 SimpleMailMessage 类即可。
(5)批量处理是指使用 Spring Batch 框架,读取并处理大量数据,按照批处理流程。粗略来看就是从文件中读取数据,然后写入数据库,但实际上比较负责,需要提供:
① 数据文件
② 读取数据,做数据字段与实体类映射的 ItemReader
③ 进行校验和处理的 ItemProcessor
④ 设置数据源、SQL 语句的 ItemWritter、
⑤ 用于注册 Job 容器的 JobRepository
⑥ 用于启动 Job 的 JobLautcher
⑦ 实际执行的任务 Job
⑧ 步骤 step ,也就是 ItemReader->ItemProcessor->ItemWriter 即读取数据->处理校验数 据->写入数据的步骤。
最后通过 JobLautcher 的 run 方法即可启动任务。
以上都以 bean 的形式在 配置类中进行配置,配置类需要使用@EnableBatchProcessing 注解开启批量处理器。
另外可以创建监听器,在 job 执行前 和 后进行输出信息等。
③ 中进行校验还可以在实体类上使用 @Size 注解对属性进行长度的校验,相应地需要自己实现 Validator 接口,要注意的是,@Size 注解只能用于字符、字符串、集合、数组上,限制长度或个数,不是用于数值上的范围校验。