第2部分 Web中的Spring
第2部分 Web中的Spring
第5章 构建Spring Web应用
5.1.2 搭建Spring MVC
配置DispatcherServlet
按照传统的方式,像DispatcherServlet这样的Servlet会配置在web.xml文件中,这个文件
会放到应用的WAR包里面
DispatcherServlet和Servlet监听器(也就是ContextLoaderListener)的关系
启用Spring MVC
多种方式来配置DispatcherServlet,与之类似,启用Spring MVC组件的方法也不
仅一种。
Spring是使用XML进行配置的,使用 <mvc:annotation-driven >启用注解驱动的Spring MVC。
最简单的Spring MVC配置就是一个带有@EnableWebMvc注解的类:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**
* @Auther: shuaihu.shen@hand-china.com
* @Date: 2018/12/4 09:13
* @Description:
*/
@Configuration
@EnableWebMvc // 启用mvc
@ComponentScan("com.web.spittr") // 启用组件扫描
public class Webconfig extends WebMvcConfigurerAdapter {
/**
* 配置JSP视图解析器
* @return 视图
*/
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
/**
* 将对静态资源的请求转发到Servlet容器中默认的Servlet上
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
需要配置视图解析器和启用组件扫描,对静态资源的处理
注意:
WebConfig现在添加了@Component-Scan注解,因此将会扫描spitter.web包来查找组件。稍后你就会看到,我们所编写的控制器将会带有@Controller注解,这会使其成为组件扫描时的候选bean。因此,我们不需要在配置类中显式声明任何的控制器。
添加了一个ViewResolver bean。更具体来讲,是Internal-ResourceViewResolver。我们只需要知道它会查找JSP文件,在查找的时候,它会在视图名称上加一个特定的前缀和后缀(例如,名为home的视图将会解析为/WEB-INF/views/home.jsp)。
最后,新的WebConfig类还扩展了WebMvcConfigurerAdapter并重写了其configureDefaultServletHandling()方法。通过调用DefaultServlet-HandlerConfigurer的enable()方法,我们要求DispatcherServlet将对静态资源的
请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本身来处理此类请求。
5.2 编写基本的控制器
在Spring MVC中,控制器只是方法上添加了@RequestMapping注解的类,这个注解声明了它们所要处理的请求。
开始的时候,我们尽可能简单,假设控制器类要处理对“/”的请求,并渲染应用的首页
/**
* @Auther: shuaihu.shen@hand-china.com
* @Date: 2018/12/13 08:59
* @Description: 超级简单的控制器
*/
@Controller
public class HomeController {
@RequestMapping(value = "/", method = GET)
public String home(){
return "home";
}
}
此时此刻运行一下项目便可以成功了。
程序清单:
- SpittrWebAppInitializer.java 核心配置文件 可以替代web.xml
- Webconfig.java 视图解析器 启用组件扫描 静态文件处理 类似于dispatcherservlet
- RootConfig.java 非核心补充文件
- HomeController.java 简单控制器
- home.jsp 访问页
测试:
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import static org.junit.Assert.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
public class HomeControllerTest {
@Test
public void testHomePage() throws Exception {
HomeController homeController = new HomeController();
// 搭建MockMvc
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(homeController).build();
// 对 "/" 执行GET请求 预期得到home视图
mockMvc.perform(get("/")).andExpect(view().name("home"));
assertEquals("home", homeController.home());
}
}
发起了对“/”的GET请求,并断言结果视图的名称为home。
它首先传递一个HomeController实例
到MockMvcBuilders.standaloneSetup()并调用build()来构建MockMvc实例。然后它使用MockMvc实例来执行针对“/”的GET请求并设置期望得到的视图名称
基础知识补充:
final变量在使用前需要初始化,static final修饰的变量在定义的时候进行初始化。
直接复制或者在构造参数中复制
5.3 接受请求的
参数传递
这个处理器方法将会处理形如“/spittles/show?spittle_id=12345”这样的请求。尽管这也可以正
常工作,但是从面向资源的角度来看这并不理想。在理想情况下,要识别的资源(Spittle)应
<u>该通过URL路径进行标示,而不是通过查询参数。</u><u>对“/spittles/12345”发起GET请求要优于</u>
<u>对“/spittles/show?spittle_id=12345”发起请求</u>。前者能够识别出要查询的资源,而后者描述的是
带有参数的一个操作——本质上是通过HTTP发起的RPC。
两种不同的参数传递方式
/**
* 展示不同数量的数据
* @param max 最大值
* @param count 数量
* @param model
* @return spitterList
*/
@RequestMapping(value = "show", method = RequestMethod.GET)
public String showSpittles(@RequestParam(value = "max",defaultValue = "MAX_VALUE",required = true) long max,
@RequestParam(value = "count",defaultValue = "DEFAULT_COUNT_SIZE",required = true) int count,
Model model) {
List<Spittle> spittleList = spittleRepository.findSpittles(max, count);
model.addAttribute("spittleList", spittleList);
return "spittles";
}
5.4 处理表单
/**
* 注册BO 带有校验
* @param spittle
* @param errors
* @return
*/
@RequestMapping(value = "register", method = RequestMethod.POST)
public String processRegistration(@Validated Spittle spittle, Errors errors) {
// 如果表单校验出差,则返回到注册页面
if (errors.hasErrors()) {
return "registerForm";
}
// 重定向到基本信息页
return "redirect:/spitter" + spittle.getUsername();
}
/**
* 通过spitter的username查找
* @param username
* @param model
* @return
*/
@RequestMapping(value = "spittle/{username}", method = RequestMethod.GET)
public String spittle(@PathVariable("username") String username, Model model) {
List<Spittle> spittleList = new ArrayList<>();
spittleList.add(spittleRepository.findByUsername(username));
model.addAttribute("spittleList", spittleList);
return "spittles";
}
Java校验API所提供的校验注解
注 解 | 描述 |
---|---|
@AssertFalse | 所注解的元素必须是Boolean类型,并且值为false |
@AssertTrue | 所注解的元素必须是Boolean类型,并且值为true |
@DecimalMax | 所注解的元素必须是数字,并且它的值要小于或等于给定的BigDecimalString值 |
@DecimalMin | 所注解的元素必须是数字,并且它的值要大于或等于给定的BigDecimalString值 |
@Digits | 所注解的元素必须是数字,并且它的值必须有指定的 @Digits(integer = 0, fraction =10 ) |
@Future | 所注解的元素的值必须是一个将来的日期 |
@Past | 所注解的元素的值必须是一个已过去的日期 |
/**
* 通过id查找
* @param spittleId
* @param model
* @return
*/
@RequestMapping(value = "spittle/{spittleId}", method = RequestMethod.GET)
public String spittle(@PathVariable("spittleId") Long spittleId, Model model) {
List<Spittle> spittleList = new ArrayList<>();
spittleList.add(spittleRepository.findOne(spittleId));
model.addAttribute("spittleList", spittleList);
return "spittles";
}
/**
* 打开注册页面
* @return
*/
@RequestMapping(value = "register", method = RequestMethod.GET)
public String showRegisterationFrom() {
return "registerForm";
}
5.5 小结
读完之后也基本上入门的内容,代码也跟着写一下,但也有生疏的地方,jsp页面标签的陌生,即使现在已经在项目上不怎么用了,尤其刚搭建项目时,由于jar包的冲突,实在尴尬,页面一直是500,又看了很多帖子,加了几个jar包就好了。
知识虽然基础,但需要系统的去认识
============================================================
第6章 渲染Web视图
本章内容:
将模型数据渲染为HTML
使用JSP视图
通过tiles定义视图布局
使用Thymeleaf视图
Spring MVC定义了一个名为ViewResolver的接口
public interface ViewResolver {
View resolveViewName(String var1, Locale var2) throws Exception;
}
public interface View {
String getContentType();
void render(Map<String, ?> var1, HttpServletRequest var2, HttpServletResponse var3) throws Exception;
}
View接口的任务就是接受模型以及Servlet的request和response对象,并将输出结果渲染到response中。
6.3 使用Apache Tiles视图定义
原始的方式:
页面定义一个通用的头部和底部。最原始的方式就是查找每个JSP模板,并为其添加头部和底部的HTML。但是这种方法的扩展性并不好,也难以维护。为每个页面添加这些元素会有一些初始成本,而后续的每次变更都会耗费类似的成本。
更好的方式是:
使用布局引擎,如Apache Tiles,定义适用于所有页面的通用页面布局。SpringMVC以视图解析器的形式为Apache Tiles提供了支持,这个视图解析器能够将逻辑视图名解析为Tile定义
6.4 使用Thymeleaf
JSP规范是与Servlet规范紧密耦合的,这意味着它只能用在基于Servlet的Web应用之中。JSP模板不能作为通用的模板(如格式化Email),也不能用于非Servlet的Web应用
为了要在Spring中使用Thymeleaf,我们需要配置三个启用Thymeleaf与Spring集成的bean:
- ThymeleafViewResolver:将逻辑视图名称解析为Thymeleaf模板视图;
- SpringTemplateEngine:处理模板并渲染结果;
- TemplateResolver:加载Thymeleaf模板
配置Thymeleaf视图解析器
package com.web.spittr.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.thymeleaf.spring3.SpringTemplateEngine;
import org.thymeleaf.spring3.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;
import org.thymeleaf.templateresolver.TemplateResolver;
/**
* @Auther: shuaihu.shen@hand-china.com
* @Date: 2018/12/4 09:13
* @Description:
*/
@Configuration
@EnableWebMvc // 启用mvc
@ComponentScan("com.web.spittr") // 启用组件扫描
public class Webconfig extends WebMvcConfigurerAdapter {
/**
* 配置JSP视图解析器
* @return
*/
@Bean
public TemplateResolver templateResolver() {
TemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
/**
* thymeleaf 视图解析器
* @param templateEngine
* @return
*/
@Bean
public ViewResolver viewResolver2(
SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
/**
* 模板引擎
* @param templateResolver
* @return
*/
@Bean
public SpringTemplateEngine templateEngine(TemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
/**
* 静态文件处理
* @param configurer
*/
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
引入Thymeleaf 真的让人感到着急,前后一直弄,指导昨天晚上十一点之后才可以,一直不能导入TemplateResolver这个类,找了很久,不知道缺失什么jar包,其实也知道方向如何,只能没有去试,jar的版本冲突,可怜的娃子,以后还是找稳定一些的,作者给的jar不用去尝试新的了。
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring3 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring3</artifactId>
<version>2.1.2.RELEASE</version>
</dependency>
=============================================================