最近在学习Spring实战第五章:利用JavaConfig代替xml文件实现Spring mvc配置,弄了好久终于用Maven实现完成了,现在将代码分享出去。
需要注意的是:只有在tomcat3.0中才支持java配置的DispatcherServlet环境,如果低于这个版本,只能使用web.xml配置
前期的Maven项目创建可以看这位博主写的,虽然比较麻烦但确实有效。
https://www.cnblogs.com/noteless/p/5213075.html
java代码目录:
webapp目录:
在这里我没有将jsp文件放在书中所设置的view文件夹,而是直接放在最外层,实现时可以自己选择,到时候改一下WebConfig里视图解析器的配置就好。
我会按照书中的大致顺序贴上代码,我的项目名称为webapp052,书中项目名称是spittr
一、pom文件
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>jiajia</groupId>
<artifactId>webapp052</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>webapp052 Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.16.Final</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.3.RELEASE</version>
</dependency>
<!--spring单元测试依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<!--spring-test4.12的版本是需要有一个依赖包的。 -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
<build>
<finalName>webapp052</finalName>
</build>
</project>
二、Spring mvc基本配置
总共有三个文件,在spittr.config文件夹下。
WebConfig配置
package 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.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import spittr.data.SpitterRepository;
import spittr.data.SpitterRepositoryimpl;
import spittr.data.SpittleRepository;
import spittr.data.SpittleRepositoryimpl;
//只有在tomcat3.0中才支持java配置的DispatcherServlet环境,如果低于这个版本,只能使用web.xml配置
@Configuration
@EnableWebMvc //启动mvc
@ComponentScan("spittr.web") //扫描这个包里的的组件
//原书为实现WebMvcConfigurerAdapter接口,但是此接口已经作废,所以用WebMvcConfigure代替
public class WebConfig implements WebMvcConfigurer{
//配置jsp视图解析器
@Bean
public ViewResolver viewResolver() {
System.out.println("视图解析启动");
InternalResourceViewResolver resolver=new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/");
resolver.setSuffix(".jsp");
//设置是否将所有spring上下文中的bean都作为请求属性访问
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
//通过这个方法要求将静态资源转发到servlet容器,而不是用DispatcherServlet
configurer.enable();
}
//只想要实现home视图的可以先不写这两个bean
@Bean
public SpittleRepository spittleRepository() {
return new SpittleRepositoryimpl();
}
@Bean
public SpitterRepository spitterRepository() {
return new SpitterRepositoryimpl();
}
}
RootConfig配置
package spittr.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.context.annotation.ComponentScan.Filter;
@Configuration
@ComponentScan(basePackages = { "spittr.data" }, excludeFilters = {
@Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class),
//不扫描web包,否则会在创建bean时报错
@Filter(type=FilterType.REGEX,pattern="spittr.web")})
public class RootConfig {
}
需要注意的是项目启动是先加载 RootConfig,随后才会加载WebConfig,所以为了防止RootConfig扫描到web里的bean从而出现报错,设置过滤防止 RootConfig扫描web里的bean,也就是说在WebConfig创建Controller类的bean时, RootConfig已经预先找到了data文件里的Repository类的bean,从而可以成功注入。
SpittrWebAppInitializer配置类
package spittr.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
@Override
protected Class<?>[] getRootConfigClasses() {
// TODO Auto-generated method stub
return new Class<?>[] {RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
// TODO Auto-generated method stub
return new Class<?>[] {WebConfig.class};
}
@Override
protected String[] getServletMappings() {
// TODO Auto-generated method stub
return new String[] { "/" };
}
}
二、基本的home视图实现
在spittr.web文件夹下新建一个HomeController类,作为控制器
package spittr.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping({"/","/homepage"}) //定义类级别的请求处理,控制器映射到“/”
public class HomeController {
@RequestMapping(method=RequestMethod.GET)
public String home() {
return "home";
}
}
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Spittr</title>
</head>
<body>
<h1>Welcome to Spittr homepage!</h1>
<a href=" <c:url value='/spittles'/> " >Spittles</a>
<a href=" <c:url value='/spitter/register'/>" > Register</a>
</body>
</html>
注意添加jstl和standard两个文件。
右键项目Run on Server运行
得到结果,注意这里我的端口号是8888,请使用自己的tomcat的端口号,一般默认为8080
三、传递数据模型到视图中
现在让我们完成spittle部分,首先创建一个spittr对象
package spittr;
import java.util.Date;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Spittle {
private final Long id;
private final String message;
private final Date time;
private Double latitude;
private Double longitude;
//在这些构造方法里我添加了一个id的属性,原书是没有的
public Spittle(Long id,String message,Date time) {
this(id,message,time,null,null);
}
public Spittle(Long id,String message,Date time,Double latitude,Double longitude) {
this.id=id;
this.message=message;
this.time=time;
this.latitude=latitude;
this.longitude=longitude;
}
public Long getId() {
return id;
}
public String getMessage() {
return message;
}
public Date getTime() {
return time;
}
public Double getLatitude() {
return latitude;
}
public Double getLongitude() {
return longitude;
}
@Override
public boolean equals(Object that) {
return EqualsBuilder.reflectionEquals(this, that, "id", "time");
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "id", "time");
}
}
然后定义一个存储用户发表日志的接口SpittleRepository
package spittr.data;
import java.util.List;
import spittr.Spittle;
public interface SpittleRepository {
//返回给定的Spittle列表
List<Spittle> findSpittles(long max ,int count);
//找到单个Spittle并返回
Spittle findone(long spittleID);
}
接下来是其接口实现,书中没有给出具体的实现类,这是我自己写的,如果只是如书中所说进行测试,可以不实现此接口。
package spittr.data;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Component;
import spittr.Spittle;
public class SpittleRepositoryimpl implements SpittleRepository{
private List<Spittle> spittleList=new ArrayList<Spittle>();
//装填spittle
public SpittleRepositoryimpl( ) {
// TODO Auto-generated constructor stub
for(long i=0;i<20;i++) {
spittleList.add(new Spittle(i,"今天很高兴"+i, new Date()));
}
}
@Override
public List<Spittle> findSpittles(long max, int count) {
// TODO Auto-generated method stub
return spittleList;
}
@Override
public Spittle findone(long spittleID) {
// TODO Auto-generated method stub
return new Spittle(spittleID, "指定的Spitttle"+spittleID, new Date());
}
}
现在我们创建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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import spittr.data.SpittleRepository;
@Controller
@RequestMapping("/spittles") //解析带有该符号的url
public class SpittleController {
private SpittleRepository spittleRepository;
@Autowired
public SpittleController(SpittleRepository spittleRepository) {
this.spittleRepository=spittleRepository;
}
//请求当前最新20个spittle
@RequestMapping(method=RequestMethod.GET)
public String spittles(Model model) {
System.out.println("------------------------s");
//求最新的20个spittle,实际上这个参数在我的具体实现类里毫无作用,因为我没有使用这个参数
model.addAttribute(spittleRepository.findSpittles(Long.MAX_VALUE, 20));
return "spittles";//请求jsp视图
}
//请求特定的单个spittle,这里采用书中的通过路径参数接受输入的办法
@RequestMapping(value="/{spittleId}" ,method=RequestMethod.GET)
public String spittlesone(Model model,@PathVariable long spittleId) {
System.out.println("------------------------spittlesone");
model.addAttribute(spittleRepository.findone(spittleId));
return "spittle";//请求jsp视图
}
}
下面是spittles和spittle的两个jsp视图
spittles.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
Hello!<br/>
<!-- 因为不可以直接访问WEB-INF下的文件,所以设置了一个超链接 -->
<a href=" <c:url value='/spittles/12345'/> " >获取一个指定的Spittle</a>
<c:forEach items="${spittleList}" var="spittle">
<li id="spittle_<c:out value='spittle.id'/>">
<div class="spittleMessage">
<c:out value="${spittle.message }"/>
</div>
<div>
<span class="spittleTime"><c:out value="${spittle.time}"/></span>
<span class="spittleLocation">
(<c:out value="${spittle.latitude}"/>,<c:out value="${spittle.longitude }"></c:out>)
</span>
</div>
</li>
</c:forEach>
<div class="spittleView">
<div class="spittleMessage"><c:out value="${spittle.message}"/></div>
<div class="spittleTime"><c:out value="${spittle.time}"/></div>
</div>
</body>
</html>
spittle.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
spittle
<div class="spittleView">
<div class="spittleMessage">
<c:out value="${spittle.message}"></c:out>
</div>
<div>
<span class="spittleTime"><c:out value="${spittle.time }"></c:out></span>
</div>
</div>
</body>
</html>
启动项目,通过home页面的spittles链接访问得到如下页面。
点击获取一个指定的Spittle
四、表单的提交与校验
在之前的home视图中,拥有一个用户注册的链接,现在我们来实现用户注册的操作。
用户在点击注册之后,应提供一个表单视图以供用户填写,在填写完毕后,应检查填写是否规范,然后跳转到注册后的用户界面。
我们先完成一个包含用户基本信息的Spitter类,通过在这个类上的属性添加注解进行表单的校验。
package spittr;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.hibernate.validator.constraints.Email;
public class Spitter {
private Long id;
@NotNull
@Size(min=5, max=16)
private String username;
@NotNull
@Size(min=5, max=25)
private String password;
@NotNull
@Size(min=2, max=30)
private String firstName;
@NotNull
@Size(min=2, max=30)
private String lastName;
//原书中有notnull注解,但是加上这个注解会在注册页面报错,因为注册页面没有添加关于此的信息输入
@Email
private String email;
public Spitter() {}
public Spitter(String username, String password, String firstName, String lastName, String email) {
this(null, username, password, firstName, lastName, email);
}
public Spitter(Long id, String username, String password, String firstName, String lastName, String email) {
this.id = id;
this.username = username;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public boolean equals(Object that) {
return EqualsBuilder.reflectionEquals(this, that, "firstName", "lastName", "username", "password", "email");
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "firstName", "lastName", "username", "password", "email");
}
}
然后再添加一个保存所有用户信息的SpitterRepository及其实现。
package spittr.data;
import spittr.Spitter;
public interface SpitterRepository {
Spitter save(Spitter spitter);
Spitter findByUsername(String username);
}
package spittr.data;
import java.util.ArrayList;
import java.util.List;
import spittr.Spitter;
public class SpitterRepositoryimpl implements SpitterRepository {
private List<Spitter> spitterList=new ArrayList<Spitter>();
//存储一个spitter并返回此spitter
@Override
public Spitter save(Spitter spitter) {
// TODO Auto-generated method stub
spitterList.add(spitter);
return spitter;
}
//通过username查找特定的用户信息
@Override
public Spitter findByUsername(String username) {
// TODO Auto-generated method stub
for(Spitter name:spitterList) {
if(name.getUsername().equals(username)) {
//找到则返回对应的spitter
return name;
}
}
return spitterList.get(0);
}
}
下面是处理表单提交和跳转的SpitterController
package spittr.web;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import spittr.Spitter;
import spittr.data.SpitterRepository;
@Controller
@RequestMapping("/spitter") //解析带有该符号的url
public class SpitterController {
private SpitterRepository spitterRepository;
@Autowired
public SpitterController(SpitterRepository spittlerRepository) {
// TODO Auto-generated constructor stub
this.spitterRepository=spittlerRepository;
}
//处理用户注册请求
@RequestMapping(value="/register" ,method=RequestMethod.GET)
public String showRegistrationForm() {
return "registerForm";
}
//处理用户注册表单的提交,注意方式为POST
@RequestMapping(value="/register" ,method=RequestMethod.POST)
public String processRegistration(@Valid Spitter spitter,Errors errors) {
//如果不符合规则,则返回注册界面
if(errors.hasErrors()) {
System.out.println("error!!"+errors);
return "registerForm";
}
//如果符合规则,则保持并重定向到用户注册后的界面
System.out.println("-----------------符合注册规则----------------");
spitterRepository.save(spitter);
return "redirect:/spitter/"+spitter.getUsername();
}
//转到用户注册完成后的profile页面
@RequestMapping(value="/{username}" ,method=RequestMethod.GET)
public String showSpitterProfile(@PathVariable String username,Model model) {
Spitter spitter=spitterRepository.findByUsername(username);
model.addAttribute("spitter",spitter);
return "profile";
}
}
下面是需要返回的视图registerForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spitter Register</title>
</head>
<body>
<h1>Spitter Register</h1>
<form method="POST">
First Name:<input type="text" name="firstName"/><br/>
Last Name:<input type="text" name="lastName"/><br/>
Username:<input type="text" name="username"/><br/>
Password:<input type="password" name="password"/><br/>
<input type="submit" value="Register"/><br/>
</form>
</body>
</html>
以及下面的profile.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Your Profile</title>
</head>
<body>
<h1>Your profile</h1>
<c:out value="${spitter.username}"></c:out><br/>
<c:out value="${spitter.firstName }"></c:out>
<c:out value="${spitter.lastName }"></c:out>
</body>
</html>
项目启动,通过home视图,可以进入注册界面,这张图的地址出现了jsessionid之类的东西,手动删去不影响程序,貌似是第一次运行系统自动生成的东西。
点击注册按钮,系统会监测是否符合规则,若符合命名规则,则跳转到用户界面。
以上就是工程的全部内容,如果有任何意见欢迎各位高手指出。
如果需要项目资源,请到以下链接下载:
https://download.youkuaiyun.com/download/weixin_43690318/11180532