开发Thymeleaf应用
简介
Thymeleaf属于视图显示技术、模板技术。
模板文件(模板表达式)+模板数据=HTML结果(性能比JSP文件要高)
JSP文件(EL+JSTL+其他标签)+模板数据=HTML结果
JSP-->Servlet-->.Class-->HTML结果
模板和JSP区别:
- 模板生成HTML界面效率高,JSP效率低
- 模板学习和使用简单,JSP复杂
使用
- 在pom.xml中定义thymeleaf包、web包
- 在application.properties配置tomcat端口
- 定义启动类,main启动
- 定义HelloController,将数据放入Model或ModelAndView
-
在src\main\resources\templates目录下定义html模板
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
server.port=8888
@SpringBootApplication
public class MyBootApplication {
public static void main(String[] args) {
SpringApplication.run(MyBootApplication.class, args);
}
}
@Controller
public class HelloController {
@RequestMapping("/hello/say1")
public ModelAndView say1() {
ModelAndView mav = new ModelAndView();
mav.setViewName("hello");
mav.getModel().put("msg", "hello");
return mav;
}
}
<!DOCTYPE html>
<html xmlns="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1 th:text="${msg}">xxx</h1>
</body>
</html>
运行之后网页源码,就相当于把msg信息拿到了xxx的位置。
循环的是HelloController中添加的集合。
each标签循环
用于判断标签的变量初始化
只显示为ture的一个p标签。
SpringBoot静态资源
SpringBoot预定义了以下几个目录,用于存放静态资源,例如jpg、css、js、html、mp4等。
- META-INF/resources 优先级最高
- resources
- static
- public 优先级最低
如果需要自定义静态资源目录,可以采用Java配置。
package cn.xdl.config
@Configuration
public class MyResourceConfiguration implements WebMvcConfigurer{
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String[] locations = {
"classpath:/mystatic/",
"classpath:/META-INF/resources/",
"classpath:/resources/",
"classpath:/static/",
"classpath:/public/"};
registry.addResourceHandler("/**")
.addResourceLocations(locations);
}
}
1.定义拦截器实现组件
package cn.xdl.interceptor
@Component
public class SomeInterceptor implements HandlerInterceptor{
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler)
throws Exception {
System.out.println("------执行拦截器preHandle方法-------");
Object user = request.getSession().getAttribute("user");
if(user==null){
//指定响应界面
response.sendRedirect("/login");
return false;
}
return true;
}
}
2.配置拦截器组件
package cn.xdl.config
@Configuration
public class MyInterceptorConfiguration implements WebMvcConfigurer{
@Autowired
private SomeInterceptor some;
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(some)
.addPathPatterns("/hello/say1");
}
}
运行测试:
对登录进行拦截,需要指定响应界面login.html
在拦截器组件定义中进行session判断,响应界面需要从一个Controller中获取。
再次测试:运行自动跳到界面。
SpringBoot异常处理
SpringBoot底层提供了一个BasicErrorController组件,有两个/error处理方法,一个返回JSON,一个返回HTML。启动自动配置后,ErrorMvcAutoConfiguration组件会创建Controller对象纳入Spring容器中。 当请求处理发生异常后,框架会采用转发方式调用/error处理。
全局处理方式
自定义一个ErrorController,继承AbstractErrorController父类,定义/error请求处理方法。
@Controller
@RequestMapping("/error")
public class MyErrorController extends AbstractErrorController{
public MyErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes);
// TODO Auto-generated constructor stub
}
@Override
public String getErrorPath() {
// TODO Auto-generated method stub
return "/error";
}
//一般请求
@RequestMapping(produces={"text/html"})
public ModelAndView errorHtml(){
ModelAndView mav = new ModelAndView();
mav.setViewName("myerror");// /templates/myerror.html
mav.getModel().put("error", "自定义错误消息");
return mav;
}
//ajax请求
@RequestMapping
@ResponseBody
public Map<Object,Object> error(){
Map<Object,Object> map = new HashMap<>();
map.put("error", "自定义错误消息");
return map;
}
}
写一个myerror.html页面
测试:
局部处理方法
采用SpringMVC中的@ExceptionHandler
@Controller
public class ExceptionController {
//访问的时候,网址后数字为正常,其他字符为异常
@RequestMapping("/exception/{id}")
public String execute(@PathVariable("id")String id){
int i = Integer.parseInt(id);
return "hello";//return 到 hello.html页面
}
//局部处理的实现方法
@ExceptionHandler//处理当前Controller异常
public ModelAndView handleException(Exception ex){
ModelAndView mav = new ModelAndView();
mav.setViewName("myerror2");
mav.getModel().put("error", ex);
return mav;
}
}
自定义反json
正常:
错误自动调用全局:
再写个myerror2页面,体现特殊局部处理:
SpringBoot AOP (spring-boot-starter-aop)
AOP简介
面向切面编程,Aspect Oriented Programming
OOP Object Oriented Programming
AOP编程以OOP为基础,将通用业务从原有业务组件抽离出来独立封装,之后再通过配置作用回去。
目的:实现业务解耦。
- 切入什么功能?(切面组件)
- 给谁切入功能?(切入点表达式)
- 什么时机切入?(通知类型)
案例:日志记录,记录调用Controller组件类型、方法、时间、执行时间
- 记录controller调用信息
- 给所有controller方法切入,within(cn.xdl.controller..*)
- 方法执行后切入,环绕通知 @Around
package cn.xdl.aop;
import java.lang.reflect.Method;
import java.util.Date;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.RequestMapping;
@Component
@Aspect
public class LogBean {
@Around("within(cn.xdl.controller..*)")
public Object exec(ProceedingJoinPoint pjp) throws Throwable{
//前置逻辑
StopWatch watch = new StopWatch();
watch.start();
Object obj = pjp.proceed();//调用目标组件方法
watch.stop();
//后置逻辑,记录日志
String targetClass = pjp.getTarget().getClass().getName();
String methodName = pjp.getSignature().getName();
//根据组件和方法名获取method对象
String uri = "";
Method[] methods = pjp.getTarget().getClass().getMethods();
for(Method m:methods){
//获取执行的Method对象
if(m.getName().equals(methodName)){
//根据Method对象获取前面的@RequestMapping注解对象
RequestMapping mapping =
m.getAnnotation(RequestMapping.class);
uri = mapping.value()[0];
}
}
System.out.println("调用的组件:"+targetClass
+" 方法名:"+methodName+" 映射请求:"+uri
+" 调用时间:"+new Date()+" 执行时间:"+watch.getTotalTimeMillis());
return obj;
}
}
结果: