最近在学习SpringCloud微服务的整合,这段时间也挺迷茫的,不太确定自己的方向,特别是前端这块。最后综合各方面的因素,决定学习Thymeleaf模版引擎,它也是SpringBoot官方推荐的模版引擎。
先来介绍下Thymeleaf:
- Thymeleaf是⾯向Web和独⽴环境的现代服务器端Java模板引擎, 能够处理HTML, XML, JavaScript, CSS甚⾄纯⽂本。
- Thymeleaf旨在提供⼀个优雅的、 ⾼度可维护的创建模板的⽅式。 为了实现这⼀⽬标, Thymeleaf建⽴在⾃然模板的概念上,将其逻辑注⼊到模板⽂件中, 不会影响模板设计原型。 这改善了设计的沟通, 弥合了设计和开发团队之间的差距。
- Thymeleaf从设计之初就遵循Web标准——特别是HTML5标准 , 如果需要, Thymeleaf允许您创建完全符合HTML5验证标准的模板。
Thymeleaf的优势:
A.Thymeleaf 在有网络和无网络的环境下皆可运行,而且完全不需启动WEB应用,即它可以让美工在浏览器查看页面的静态效果,也可以让程序员在服务器查看带数据的动态页面效果。这是由于它支持 html 原型,然后在 html 标签里增加额外的属性来达到模板+数据的展示方式。浏览器解释 html 时会忽略未定义的标签属性,所以 thymeleaf 的模板可以静态地运行;当有数据返回到页面时,Thymeleaf 标签会动态地替换掉静态内容,使页面动态显示。
B.Thymeleaf 开箱即用的特性。它提供标准和spring标准两种方言,可以直接套用模板实现JSTL、 OGNL表达式效果,避免每天套模板、该jstl、改标签的困扰。同时开发人员也可以扩展和创建自定义的方言。
C.Thymeleaf 提供spring标准方言和一个与 SpringMVC完美集成的可选模块,可以快速的实现表单绑定、属性编辑器、国际化等功能。
总的来说,我个人认为:Thymeleaf最大的优势就是完美的支持H5及前端开发人员可以实现与后台开发人员的无缝交接,这也是实现前后端分离的最主要的技术。
关于Thymeleaf的资料大家自行上网查看,我今天主要来跟大家分享SpringClou与Thymeleaf模版引擎整合的案例(ORM框架采用的是Mybatis)。
首先,搭建Eureka服务器。然后搭建一个服务提供者和服务消费者的微服务,并将这两个微服务注册到Eureka服务器中。具体看如下代码:
//创建User对象,其中grade表示User读过的班级list
public class User {
private Integer uid;
private String userName;
private Integer age;
private List grade;
public User(Integer uid, String userName, Integer age, List grade) {
this.uid = uid;
this.userName = userName;
this.age = age;
this.grade = grade;
}
public User(){}
public long getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public List getGrade() {
return grade;
}
public void setGrade(List grade) {
this.grade = grade;
}
}
//创建Grade对象
public class Grade {
private Integer gid;
private String userName;
private String gradeName;
private String teacherName;
public Grade(Integer gid, String userName,String gradeName, String teacherName) {
this.gid = gid;
this.userName = userName;
this.gradeName = gradeName;
this.teacherName = teacherName;
}
public Grade(){}
public long getGid() {
return gid;
}
public void setGid(Integer gid) {
this.gid = gid;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGradeName() {
return gradeName;
}
public void setGradeName(String gradeName) {
this.gradeName = gradeName;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
}
数据库设计如下:
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`uid` int(9) NOT NULL AUTO_INCREMENT,
`userName` varchar(8) NOT NULL,
`age` tinyint(4) NOT NULL,
PRIMARY KEY (`uid`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `t_grade`;
CREATE TABLE `t_grade` (
`gid` int(9) NOT NULL AUTO_INCREMENT,
`userName` varchar(8) NOT NULL,
`gradeName` varchar(12) NOT NULL,
`teacherName` varchar(8) NOT NULL,
PRIMARY KEY (`gid`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
Mapper映射文件:
insert into t_user(userName,age) values(#{userName},#{age});
insert into t_grade(userName,gradeName,teacherName)
values
(#{item.userName},#{item.gradeName},#{item.teacherName})
先说说我在用Mybatis映射对象时遇到的问题:
1.当我把标签的 标签添加 判断的时候,即如下
and t1.userName = #{userName}
Mybatis报下异常:
org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'userName' in 'class java.lang.String'
只需要用删除: ,就不会报错了。
2.上面的User和Grade都有两个构造器,一个是有参构造器,一个是无参构造器。下面来说说它们的作用:
A.有参构造器的作用:必须要有默认的构造器,否则,SpringCloud Feign根据json字符串转换成User时会抛出异常.
B.无参构造器的作用:预防Mybatis映射报异常.
当我把无参构造器去掉时,以User为例:
去掉 public User(){}
Mybatis报如下异常:
nested exception is org.apache.ibatis.executor.ExecutorException: No constructor found in com.xue.test.domain.User matching [java.lang.Integer, java.lang.String, java.lang.Integer, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String]] with root cause
所有以后创建domain对象的时候,记得要同时创建有参构造器及无参构造器
导入Thymeleaf的依赖:
org.springframework.boot
spring-boot-starter-thymeleaf
application.yml中添加如下配置:
#thymelea模板配置
spring:
thymeleaf:
cache: false
mode: HTML5
encoding: UTF-8
servlet:
content-type: text/html
prefix: classpath:/templates
suffix: .html
resources:
chain:
strategy:
content:
enabled: true
paths: /**
我是使用Feign进行调用的,整合了Hytrix,代码如下:
//定义FeignClient接口
@FeignClient(name="server-provide",fallback = UserHystrixClient.class)
public interface UserFeignClient {
@GetMapping("/user/{userName}")
User findUserByName(@PathVariable("userName") String userName);
}
//定义回退方法的类
@Component
public class UserHystrixClient implements UserFeignClient {
@Override
public User findUserByName(String userName) {
User user = new User();
user.setUid(0);
user.setUserName("Hystrix");
user.setAge(18);
ArrayList gradeList = new ArrayList<>();
Grade grade = new Grade();
grade.setGid(0);
grade.setUserName("Hystrix");
grade.setGradeName("Hystrix");
grade.setTeacherName("Hystrix");
gradeList.add(grade);
user.setGrade(gradeList);
return user;
}
}
UserController的调用代码:
@RestController
public class UserController {
@Resource
private UserFeignClient userFeignClient;
@GetMapping("/user/{userName}")
public ModelAndView showUserDetails(@PathVariable String userName){
User user = userFeignClient.findUserByName(userName);
List gradeList = user.getGrade();
for(Grade grade:gradeList){
grade.getTeacherName();
}
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("user",user);
//记得一定要将"/"加上
modelAndView.setViewName("/test");
return modelAndView;
}
}
目录结构:
使用Thymeleaf后test.html的写法:
Test
uId
userName
age
gid
gradeName
teacherName
SpringClou+Thymeleaf整合步骤就演示完了。当前只做了数据的展示,后续我会更新Thymeleaf表单数据的提交及Thymeleaf的ajax提交的做法。