记录开发一个完整SpringBoot项目的过程。
一、项目初始化
1.1 使用 Liquibase作为数据库迁移工具
第一步:引入 Liquibase 依赖:
<!-- 数据库迁移工具: liquibase-->
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
</dependency>
注意,于此同时需要引入: spring-boot-starter-data-jpa 的依赖,否则,启动SpringBoot项目,数据库表不能创建。
第一步:编写 db/changelog/db.changelog-master.yaml 文件
1.2 SpringBoot集成MyBatis
1.3 SpringSecurity logout 出现404
spring security 在开启 csrf 防护的情况下, /logout 必须以post的方式提交。使用Thymeleaf时,表单如下:
<form th:action="@{/logout}" method="post" class="form-inline my-2 my-lg-0">
<button class="btn btn-outline-secondary my-2 my-sm-0" type="submit">退出登录</button>
</form>
二、thymeleaf 模板 ,html中遇到的问题
3.1 An invalid form control with name='' is not focusable.
出现该错误的原因是chrome发现了有隐藏(display:none)的required需求元素,所以会出错。
将ng-show改为ng-if,从隐藏标签变为移除dom,可以避免这个错误。
3.2 sec标签 不起作用
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
添加依赖:
<!-- thymeleaf 使用Spring Security进行页面保护,需要配置的方言-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
<version>${thymeleaf-extras-springsecurity5.version}</version>
</dependency>
三、项目使用jquery遇到的问题
3.1 ajax 400错误
出现400错误,是由于ajax传递的参数有问题,应该讲data转换成json格式:使用 JSON.stringify() 函数
// ajax 参数
var data = JSON.stringify({"currentPage": currentPageNum, "pageSize": pageSize, "eid": eid});
ajax的代码如下:
function ajaxFindPage(headers, data, url) {
$.ajax({
type: "POST",
dataTypes: "json",
contentType: "application/json",
url: url,
data: data,
headers: headers,
success: function (response) {
// 结果的状态
var status = response.status;
if (status == 0) {
var result = response.result;
console.log(result);
} else {
console.error("Ajax Exception: " + url);
}
}
});
}
controller的代码如下:
@RequestMapping(value = "/findPageCurrentUserEdmApplyOrdersByQuery", method = RequestMethod.POST)
@ResponseBody
public ResponseResult findPageCurrentUserEdmApplyOrdersByQuery(@RequestBody EdmApplyOrderQuery edmApplyOrderQuery){
.......
}
四、发送邮件
@Autowired
private JavaMailSender javaMailSender;
@Autowired
private TemplateEngine templateEngine;
@Override
public void sendThymeleafEmail(EdmLiuZhuanEmailParameters edmLiuZhuanEmailParameters) {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
MimeMessageHelper helper = null;
try {
helper = new MimeMessageHelper(mimeMessage);
.........
}
4.1 遇到这么一个问题:
java.lang.IllegalStateException: Not in multipart mode - create an appropriate MimeMessageHelper via a constructor that takes a 'multipart' flag if you need to set alternative texts or add inline elements or attachments.
解决方案:
helper = new MimeMessageHelper(mimeMessage, true);
4.2 附件名称过长,接收端收到的是乱码文件
解决方案: 在发邮件的功能上添加一句配置:
// 解决附件名称过程,发送乱码问题 System.setProperty("mail.mime.splitlongparameters", "false");
五、下载附件
关于: attachment 和 inline的区别
设置attachment ,浏览器会老老实实地显示另存为的对话框;设置inline,浏览器都会自动尝试用已知关联的程序打开文件。
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
response.setHeader("Content-Disposition", "inline; filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
六、Mybatis
遇到下面一个错误:
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'roleName' in 'class java.lang.String'
需要在参数前加上 @Param 注解
/**
* 根据用户权限名称查询用户
* @param roleName
* @return
*/
@Select({"<script>",
"SELECT b1.`eid`, b1.`username`, b1.`password`, b1.`email`, b1.`department`, b1.`level` ",
"FROM `edmers` b1 ",
"inner join (",
"select t2.eid from edmer_role_relation t2 inner join edm_roles t3 ",
"on t2.rid = t3.rid ",
"where 1=1 ",
"<if test='roleName != null'>",
"and t3.role_name=#{roleName}",
"</if>",
")b2 on b1.eid=b2.eid",
"</script>"})
@Results(value = {@Result(id = true, column = "eid", property = "eid"),
@Result(column = "username", property = "username"),
@Result(column = "password", property = "password"),
@Result(column = "email", property = "email"),
@Result(column = "department", property = "department"),
@Result(column = "level", property = "level"),
@Result(property = "roles", column = "eid", javaType = List.class,
many = @Many(select = "com.edm.edmfetchdataplatform.mapper.RoleMapper.findRoleByEid"))
})
List<Edmer> findEdmersByRoleName(@Param("roleName") String roleName);
项目部署,部署到正式环境上
错误:java.sql.SQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times (参考: https://www.imooc.com/qadetail/256163)
报出这个错误,可能原因:
1、检查MySQL数据库服务是否正常(包含检查服务名和密码),如果不正常,修复至正常为止;
2、maven工程中导入的mysql的jar版本和你的MySQL版本不相符,必须相一致才行!比如,你安装的MySQL是8.x,必须使用高版本对应的mysql-connector-java-8.x.x,在MySQL官网下载对应jar时提示如下:MySQL Connector/J 8.0 is highly recommended for use with MySQL Server 8.0, 5.7, 5.6, and 5.5. Please upgrade to MySQL Connector/J 8.0.
3、连接数据库相关的属性和值不正确或缺失,按照报错提示修改或更新即可。
注:我直接将maven工程导入eclipse,修改过数据源相关属性后,启动也报同样的错误,但是MySQL服务是正常的,后面检查发现,我的MySQL安装的是高版本(8.0.11),而工程对应的mysql连接jar包是5.x版本,将低版本替换为mysql-connector-java-8.0.11.jar,同步更新对应的连接属性,启动成功。
主要替换的内容(有好几处,有些在xml配置文件中,有些在java代码中,替换时全文搜索):
1、将所有的drivername值都从com.mysql.jdbc.Driver修改为com.mysql.cj.jdbc.Driver
2、在url的参数后面新增时区参数:&serverTimezone=UTC
3、修改url连接参数中的值更新为:zeroDateTimeBehavior=CONVERT_TO_NULL