Spring实战笔记——构建Spring Web应用程序
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Spring实战笔记——构建Spring Web应用程序,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含13632字,纯文字阅读大概需要20分钟。
内容图文
Spring MVC起步
下图展示的是请求使用Spring MVC所经历的所有站点。
DispatcherServlet
:是前端控制器,主要用来将请求发送给Spring MVC控制器- 处理器映射:应用程序中往往有许多控制器,前端控制器需要知道将请求发送到哪一个控制器,因此处理映射可以用来指定需要发送的控制器。
- 处理器:用来处理请求,并返回数据
- 模型及逻辑视图名:是控制器返回的用户数据以及视图名
- 视图解析器:用来解析逻辑视图名,并匹配一个特定的视图实现
- 视图:将数据模型进行渲染输出,最后响应给客户端
搭建Spring MVC
配置DispatcherServlet
DispatcherServlet
是Spring MVC的核心
配置maven
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ruian.Spring</groupId>
<artifactId>SpringMvc</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--Mybatis-spring-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--JSP-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
</dependency>
<!--spring系列-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.24.RELEASE</version>
</dependency>
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<!--jsp-jstl-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
<build>
<!--处理资源导出问题-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
配置前端控制器
package spittr.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
//指定配置类,加载上下文时读取配置类中的bean
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
//配置DispatcherServlet映射为'/'
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
DispatcherServlet
启动的时候会创建Spring应用上下文,并加载配置文件或配置类中所声明的bean。getServletConfigClasses()
加载上下文时读取配置类中的beanDispatcherServlet
用来加载包含Web组件的bean,如控制器。而ContextLoaderListener
用来加载应用中其他的bean,这些bean通常是驱动应用后端的中间件和数据层组件。AbstractAnnotationConfigDispatcherServletInitializer
会同时创建DispatcherServlet
和ContextLoaderListener
,getServletConfigClasses()
返回的带有@Configuration
注解的类将会用来定义DispatcherServlet
应用上下文中的bean。getRootConfigClasses()
方法返回的带有@Configuration
注解的类将会用来配置ContextLoaderListener
创建的应用上下文的bean。
启用Spring MVC
一个简单的Spring MVC配置就是一个带有@EnableWebMvc
注解的类
package spittr.web;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@EnableWebMvc
public class WebConfig {
}
以上代码需要解决的问题:
- 配置视图解析器,默认视图解析器会找ID与视图名称匹配的bean,并且查找的bean要实现View接口。
- 启用组件扫面,否则Spring只会找到显示声明在配置类中的控制器
- DispatcherServlet会处理所有的请求,包括静态资源的请求
改进WebConfig
package spittr.web;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
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
@ComponentScan("spittr.web")
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
//配置JSP视图解析器
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();
}
}
编写控制器
Spring MVC控制器只是在方法上添加@RequestMapping
注解的类。
package spittr.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
//编写控制器
@Controller
public class HomeController {
@RequestMapping(value = "/", method = GET)
public String home(){
return "home";
}
}
编写jsp页面
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Spitter</title>
<link rel="stylesheet"
type="text/css"
href="<c:url value="/resources/style.css" />" >
</head>
<body>
<h1>Welcome to Spitter</h1>
<a href="<c:url value="/spittles" />">Spittles</a> |
<a href="<c:url value="/spitter/register" />">Register</a>
</body>
</html>
启动tomcat服务器测试页面
测试控制器
package spittr.web;
//测试控制器
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
public class HomeControllerTest {
@Test
public void testHomePage() throws Exception{
HomeController controller = new HomeController();
//搭建MockMvc
MockMvc mockMvc = standaloneSetup(controller).build();
//对“/”执行get请求,并期望得到home视图
mockMvc.perform(get("/")).andExpect(view().name("home"));
}
}
利用这种方法进行测试Controller可以不用启动web服务器
定义级别的请求处理
package spittr.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
//编写控制器
@Controller
@RequestMapping("/")
public class HomeController {
@RequestMapping(method = GET)
public String home(){
return "home";
}
}
@RequestMapping可以存在多个参数如:@RequestMapping({"/", "/homepage"})
传递模型数据到视图中
定义一个数据访问的Repository接口
package spittr.data;
import java.util.List;
public interface SpittleRepository {
/**
*
* @param max : 表示Spittle ID属性的最大值
* @param count:表明返回多少个Spittle对象
* @return
*/
List<Spittle> findSpittles(long max, int count);
}
创建Spittle类
package spittr.data;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import java.util.Date;
public class Spittle {
private final Long id;
private final String message;
private final Date time;
private Double latitude;
private Double longitude;
public Spittle(String message, Date time) {
this(null, message, time, null, null);
}
public Spittle(Long id, String message, Date time, Double longitude, Double latitude) {
this.id = id;
this.message = message;
this.time = time;
this.longitude = longitude;
this.latitude = latitude;
}
public long getId() {
return id;
}
public String getMessage() {
return message;
}
public Date getTime() {
return time;
}
public Double getLongitude() {
return longitude;
}
public Double getLatitude() {
return latitude;
}
@Override
public boolean equals(Object that) {
return EqualsBuilder.reflectionEquals(this, that, "id", "time");
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "id", "time");
}
}
创建测试类
@Test
public void shouldShowRecentSpittles() throws Exception{
List<Spittle> expectedSpittles = createSpittleList(20);
SpittleRepository mockRepository = Mockito.mock(SpittleRepository.class);
when(mockRepository.findSpittles(Long.MAX_VALUE, 20))
.thenReturn(expectedSpittles);
SpittleController controller = new SpittleController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller).setSingleView(
new InternalResourceView("/WEB-INF/views/spittles.jsp")
).build();
mockMvc.perform(get("/spittles"))
.andExpect(view().name("spittles"))
.andExpect(model().attributeExists("spittleList"))
.andExpect(model().attribute("spittleList", hasItems(expectedSpittles.toArray())));
}
private List<Spittle> createSpittleList(int count) {
List<Spittle> spittles = new ArrayList<>();
for(int i = 0; i < count; i++){
spittles.add(new Spittle("Spittle " + i, new Date()));
}
return spittles;
}
这个测试中,首先需要创建SpittleRepository接口的mock实现,并且在MockMvc构造器上调用了setSingleView()
,这样mock框架就不用解析视图控制器中的视图名
编写SpittleController
package spittr.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import spittr.data.SpittleRepository;
@Controller
@RequestMapping("/spittles")
public class SpittleController {
private SpittleRepository spittleRepository;
//注入SpittleRepository
@Autowired
public SpittleController(SpittleRepository spittleRepository){
this.spittleRepository = spittleRepository;
}
@RequestMapping(method = RequestMethod.GET)
public String spittles(Model model){
//将spittle添加到模型中
model.addAttribute(spittleRepository.findSpittles(Long.MAX_VALUE, 20));
return "spittles";
}
}
该控制器中的spittles()方法中给定了一个Model作为参数,这样spittles()
方法就可以将Repository中获取的Spittle列表填充到模型中。Model本质上是一个map,它会被传送至view,因此数据可以提供给客户端。如果在调用addAttribute()
方法时没有指定key,那么就会根据值的对象类型推断确定,比如代码中传入的参数属性是List
在addAttribute()
也可以指定key
model.addAttribute("spittleList", spittleRepository.findSpittles(Long.MAX_VALUE, 20))
model.addAttribute()
也可被替代为model.put()
接受请求的输入
Spring MVC允许多种方式将客户端中的数据传送到控制器的处理器方法中,包括:
- 查询参数(Query Parameter)
- 表单参数(Form Parameter)
- 路径变量(Path Variable)
处理查询参数
使用@RequestParam
注解
@RequestMapping(method = RequestMethod.GET)
public List<Spittle> spittles(
@RequestParam("max") Long max,
@RequestParam("count") int count
){
return spittleRepository.findSpittles(max, count);
}
添加测试
//测试分页
@Test
public void shouldShowPagedSpittle() throws Exception{
List<Spittle> expectedSpittle = createSpittleList(50);
SpittleRepository mockRepository = mock(SpittleRepository.class);
when(mockRepository.findSpittles(238900, 50))
.thenReturn(expectedSpittle);
SpittleController controller = new SpittleController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller).setSingleView(
new InternalResourceView("/WEB-INF/views/spittles.jsp")
).build();
mockMvc.perform(get("/spittles?max=238900&count=50"))
.andExpect(view().name("spittles"))
.andExpect(model().attributeExists("spittleList"))
.andExpect(model().attribute("spittleList", hasItems(expectedSpittle.toArray())));
}
为路径参数设置默认值
@RequestMapping(method = RequestMethod.GET)
public List<Spittle> spittles(
@RequestParam(value = "max", defaultValue = "9223372036854775807") Long max,
@RequestParam(value = "count", defaultValue = "20") int count
){
return spittleRepository.findSpittles(max, count);
}
尽管defaultValue属性给定的是String类型的值,但是当绑定到方法的max时,它会转换为Long类型。
通过路径参数接受输入
利用@RequestParam("spittle_id")
可以用来处理形如/spittles/show?spittle_id=10
这样的请求,而@PathVariable("spittle_id")
可以处理/spittle/123
这样的请求,如果对'/spittle/456'发送请求,那么会将456
传递进来,作为spittle_id
的值。
编写控制器
@RequestMapping(value = "/{spittleId}",method = RequestMethod.GET)
public String spittles(
@PathVariable(value = "spittleId") Long spittleId,
Model model
){
model.addAttribute(spittleRepository.findOne(spittleId));
return "spittle";
}
当@PathVaribale属性的值,最有又作为方法的参数名称可以省略@PathVaribale中的value属性
@RequestMapping(value = "/{spittleId}",method = RequestMethod.GET)
public String spittles(
@PathVariable Long spittleId,
Model model
){
model.addAttribute(spittleRepository.findOne(spittleId));
return "spittle";
}
编写测试类
@Test
public void testSpittle() throws Exception {
Spittle expectedSpittle = new Spittle("hello", new Date());
SpittleRepository mockRepository = mock(SpittleRepository.class);
when(mockRepository.findOne(123))
.thenReturn(expectedSpittle);
SpittleController controller = new SpittleController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller).build();
mockMvc.perform(get("/spittles/123"))
.andExpect(view().name("spittle"))
.andExpect(model().attributeExists("spittle"))
.andExpect(model().attribute("spittle", expectedSpittle));
}
处理表单
内容总结
以上是互联网集市为您收集整理的Spring实战笔记——构建Spring Web应用程序全部内容,希望文章能够帮你解决Spring实战笔记——构建Spring Web应用程序所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。