Spring实战-SpringWeb

构建Spring Web整个过程的解析

1. 请求过程

2. 搭建Spring MVC

2.1. 配置DispatcherServlet

AbstractAnnotationConfigDispatcherServletInitializer

在Servlet环境下,容器在类路径查找javax.servlet.ServletContainerInitializer接口实现类

Spring中实现名为SpringServletContainerInitializer类并查找WebAplicationInitializer类

AbstractAnnotationConfigDispatcherServletInitializer就是一个WebAplicationInitializer

DispatcherServlet加载包含Web组件的bean,控制器,视图解析器以及处理器映射

ContextLoaderListener 加载应用中驱动应用后端的中间层和数据层组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{

//返回带有@Configuration注解的类来配置ContextLoaderListener创建的应用上下文中的bean
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] {RootConfig.class};
}

//返回带有@Configuration注解的类用来定义DispatcherServlet应用上下文中的bean
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] {WebConfig.class};
}

//映射路径
@Override
protected String[] getServletMappings() {

return new String[]{"/"};
}
}

WebConfig.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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;

@Configuration
@EnableWebMvc //启用Spring MVC
@ComponentScan(basePackages="com.runnaccpeted.controller")
public class WebConfig extends WebMvcConfigurerAdapter{

//JSP视图解析器
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}

//静态资源的处理
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}

RootConfig.class

1
2
3
4
@Configuration
@ComponentScan(basePackages={"com.runnaccpeted"},excludeFilters={@Filter(type=FilterType.ANNOTATION,value=EnableWebMvc.class)})
public class RootConfig {
}

配置控制器

解析 /WEB-INF/views/home.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.runnaccpeted.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller //=@Component
public class HomeController {

@RequestMapping(value="/",method=RequestMethod.GET)
public String home(){
return "home"; //渲染视图名
}
}

视图 home.jsp

1
2
3
4
5
6
7
8
9
10
11
12
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Home</h1>
</body>
</html>

测试控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import org.junit.Test;

import com.runnaccpeted.controller.HomeController;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
public class HomeControllerTest {

@Test
public void test() throws Exception{
HomeController home = new HomeController();
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(home).build();
// 对“/”执行GET请求 预期得到home视图
mockMvc.perform(get("/")).andExpect(view().name("home"));
}

}

3. 传递模型数据

model是一个map集合,可以把集合数据传递给视图

1
2
3
4
5
6
7
8
import org.springframework.ui.Model;

@RequestMapping(method=RequestMethod.GET)
public String show(Model model){
List<User> list=userService.show(Long.MAX_VALUE, 20);
model.addAttribute("list",list);
return "list";
}

访问数据

1
2
3
4
5
6
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<c:forEach items="${list}" var="user">
<c:out value="${user.id}"></c:out>
<c:out value="${user.name}"></c:out>
</c:forEach>

4. 接受请求输入

  • 查询参数

    /Users?max=230&count=50

    @RequestParam

1
2
3
4
5
6
7
8
9
10
private static final long MAX=Long.MAX_VALUE;

@RequestMapping(method=RequestMethod.GET)
public String show(
@RequestParam(value="max",defaultValue="MAX") Long max,
@RequestParam(value="count",defaultValue="20") int count, Model model){
List<User> list=userService.show(Long.MAX_VALUE, 20);
model.addAttribute("list",list);
return "list";
}
  • 路径参数输入

    PathVariable

    /Users/123

1
2
3
4
5
@RequestMapping(value="/{userId}",method=RequestMethod.GET)
public void show(@PathVariable("userId")long userId,Model model){
model.addAttribute("list",userService.findOne(userId));
return "selectbyId";
}
  • 表单输入

    /Users/register

1
2
3
4
5
@RequestMapping("/register",method=RequestMethod.POST)
public void register(User user){
userService.save(user);
return "redirect:/Users/"+user.getId();
}
  • 校验表单属性

    javax.validation.constraints.*;

    导入 validation-api-1.1.0.beta1.jar

    注解 描述
    @AssertFalse 注解元素必须是Boolean类型,值为false
    @AssertTrue 注解元素必须是Boolean类型,值为true
    @DecimalMax(“”) 元素为数字,值小于等于给定的BigDecimalString值
    @DecimalMin(“”) 元素为数字,值大于等于给定的BigDecimalString值
    @Digits 元素为数字,值必须有指定的位数 @Digits(fraction = 0, integer = 0)
    @Future 元素值必须是一个将来的日期
    @Max 元素为数字,值小于等于给定的值 @Max(value = 0)
    @Min 元素为数字,值大于等于给定的值 @Min(value = 0)
    @NotNull 元素值不为null
    @Null 元素值必须为null
    @Past 元素值必须是一个过去的日期
    @Pattern 元素值匹配给定的正则表达式 @Pattern(regexp = “”)
    @Size 元素值为String,集合,数组,@Size(min=5,max=23)

    使用检验注解

    1
    2
    3
    4
    5
    6
    7
    8
    9
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Size;
    public class User {
    private int id;

    @NotNull
    @Size(min=5,max=23)
    private String name;
    }

    验证

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import javax.validation.Valid;
    import org.springframework.validation.Errors;

    @RequestMapping("/register")
    public String register(@Valid User user,Errors errors){
    if (errors.hasErrors()) {
    return "register"; //返回注册页
    }
    return "show";
    }

5. 渲染Web视图

SpringMVC中定义了名为ViewResolver的接口,resolveViewName方法传入视图名和Locale对象

1
2
3
4
5
6
7
package org.springframework.web.servlet;
import java.util.Locale;
public abstract interface ViewResolver
{
public abstract View resolveViewName(String paramString, Locale paramLocale)
throws Exception;
}

从中的view 接受了request,response对象,结果渲染给response

1
2
3
4
5
6
7
8
9
10
11
package org.springframework.web.servlet;

import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public abstract interface View
{
public abstract void render(Map<String, ?> paramMap, HttpServletRequest paramHttpServletRequest, HttpServletResponse paramHttpServletResponse)
throws Exception;
}

Spring定义的13种视图解析器

视图解析器 描述
BeanNameViewResolver 视图解析为Spring应用上下文的bean
ContentNegotiatingViewResolver 考虑客户端需要的内容类型来解析视图,委托给另外一个能够产生对应内容类型的视图解析器
InternalResourceViewResolver 解析为内部资源 .jsp
JasperReportViewResolver 解析为JasperReport定义
ResourceBundleViewResolver 资源bundle 属性文件
TitlesViewResolver 解析为Apache Title定义
UrlBasedViewResolver 根据视图的名称解析视图
VelocityLayoutViewResolver 解析为Velocity布局
VelocityViewResolver 解析为Velocity模版
XmlViewResolver 解析为xml特定xml文件中的bean定义
XsltViewResolvet 解析为XSLT转换后的结果

InternalResourceViewResolver

1
2
3
4
5
6
7
8
9
//JSP视图解析器
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}

xml配置

1
2
3
4
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>

5.1. Spring 的jsp标签库

commandName构建模型对象上下文信息

1
2
3
4
5
@RequestMapping("/register")
public String show(Model model){
model.addAttribute(new User());
return "form";
}

input的value属性值会设置为模型对象中path属性对应的值

<sf:input path=”id”/> == < input name=”id” value=”0” type=”text”/>

1
2
3
4
5
6
7
<%@taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>

<sf:form method="POST" commandName="user">
<sf:input path="id"/> <!-- < input name="id" value="0" type="text"/> -->
<sf:input path="name"/>
<sf:password path="password"/>
</sf:form>

错误展示

path设定对象中的属性

1
2
3
<sf:errors path="id"/>
==
<span id="user.errors"> </span>

添加样式

*表示所有属性

element 表示错误渲染在div上

1
2
3
4
5
6
7
<sf:errors path="*" element="div" cssClass="errors"/>

<style>
div.errors{
font-color:#f00;
}
</style>

错误设置在每个属性上

1
2
3
4
5
6
7
8
9
<sf:label path="name" cssErrorClass="error"></sf:label>

<label for="name" class="error"></label>

<style>
label.error{
color:red;
}
</style>

5.2. 错误信息展示

1
2
3
 @NotNull
@Size(min=5,max=23,message="{name.size}")
private String name;

在根目录下创建 ValidationMessages.properties

1
name.size=Last name must be between {min} and {max} characters long.

6. spring通用标签库

<s:message />

1
2
3
4
<%@ taglib uri="http://www.springframework.org/tags" prefix="s"%>

<!--根据给定的编码获取信息,进行渲染行为 -->
<s:message code="login.welcome"/>

实现MessageSource接口

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

@Bean
public MessageSource messageSource(){
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
//服务器文件系统目录下查找信息基于“messages”的文件名 messagesXXX.properties
messageSource.setBasename("file:///etc/messages");
messageSource.setCacheSeconds(10);
return messageSource;
}

messages.properites

1
login.welcome=Welcome!

<s:url />

htmlEscape=”true” 展现 url内容到web页面上

1
2
3
4
5
<s:url href="/Users/register" var="register" scope="request" htmlEscape="true">
<s:param name="id" value="60"></s:param>
<s:param name="name" value="wt"></s:param>
</s:url>
<a href="${register}"></a>

<s:escapeBody />

1
2
3
4
5
6
7
<s:escapeBody>
<h1>
Hello
</h1>
</s:escapeBody>

&lt;h1&gt;Hello&lt;/h1&gt;
本文结束  感谢您的阅读
  • 本文作者: Wang Ting
  • 本文链接: /zh-CN/2019/09/21/Spring实战-SpringWeb/
  • 发布时间: 2019-09-21 21:16
  • 更新时间: 2022-10-24 20:38
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!