天天看點

第5章 建構Spring Web 應用程式 --筆記1

概述:

Spring的Web架構就是為了幫你解決這些關注點而設計的。SpringMVC基于模型-視圖-控制器(Model-View-Controller,MVC)模式實作,它能夠幫你建構像Spring架構那樣靈活和松耦合的Web應用程式。

第5章 建構Spring Web 應用程式 --筆記1

5.1 搭建SpringMVC

配置DispatcherServlet

這個不是基于web,而是通過java類來配置

package com.jack.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
 * 在Servlet3.0環境中,容器會在類路徑中查詢實作
 * javax.servlet.ServletContainerInitializer 接口的類,如果發現的話,就會用它來配置Servlet容器
 * @author Administrator
 *
 */
public class SpittrWebAppInitializer 
	extends AbstractAnnotationConfigDispatcherServletInitializer{

	
	@Override
	protected Class<?>[] getRootConfigClasses() {
		return new Class<?>[]{RootConfig.class};
	}

	@Override
	protected Class<?>[] getServletConfigClasses() {
		return  new Class<?>[]{WebConfig.class};
	}

	/* 
	 * 将DispatchServlet映射到"/"
	 * (non-Javadoc)
	 * @see org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer#getRootConfigClasses()
	 */
	@Override
	protected String[] getServletMappings() {
		
		return new String[] {"/"};
	}

}
           

簡單來說,tomcat會自動加載實作AbstractAnnotationConfigDispatcherServletInitializer 類

1.配置DispatcherServlet請求映射

2.配置ApplicationContext

2.配置webApplicationContext

package com.jack.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.springframework.web.servlet.view.InternalResourceViewResolver;

/**加載Web相關的bean
 * 
 * @author Administrator
 *
 */

@Configuration
@EnableWebMvc //相當于<mvc:annotation-driven> 啟用SpringMVC
@ComponentScan("com.jack")     //啟用元件掃描包名
public class WebConfig
	extends WebMvcConfigurerAdapter{

	/**
	 * 配置JSP視圖解析器
	 * @return
	 * /WEB-INF/views/home.jsp
	 */
	@Bean
	public ViewResolver viewResolver(){
		InternalResourceViewResolver resolver = 
				new InternalResourceViewResolver();
		resolver.setPrefix("/WEB-INF/views/");
		resolver.setSuffix(".jsp");
		resolver.setExposeContextBeansAsAttributes(true);
		return resolver;
	}
	
	/**
	 * 新的WebConfig類還擴充了WebMvcConfigurerAdapter并重寫了其configureDefaultServletHandling()方法。通過調用DefaultServlet-HandlerConfigurer的enable()方法,
	 * 我們要求DispatcherServlet将對靜态資源的請求轉發到Servlet容器中預設的Servlet上,
	 * 而不是使用DispatcherServlet本身來處理此類請求。
	 * (non-Javadoc)
	 * @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configureDefaultServletHandling(org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer)
	 */
	@Override
	public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer){
		configurer.enable();
	}
}
           

總結:@EnableWebMvc 啟動SpringMVC @ComponentScan 配置掃描bean,

在配置視圖解析器和靜态資源過濾給預設Servlet

package com.jack.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@ComponentScan(basePackages={"com.jack"},
		excludeFilters={@Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)})
public class RootConfig {

}
           

開始寫簡單的控制類

package com.jack.controller;

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

@Controller //聲明為一個控制器
public class HomeController {

	@RequestMapping(value={"/","/homepage"}, method=RequestMethod.GET) //處理"/"的GET請求
	public String home(){
		return "home"; //視圖名為home
		
	}
}
           

總結:

1.注意在類上寫上@Controller

2.在方法寫url路徑的映射@RequestMapping(value={"/","homepage"}) 表示 "/" 和 "homepage" 都會被這個控制器處理

3.傳回"home"會被視圖解析器處理變成/WEB-INF/views/home.jsp

測試類:

package com.jack.controller;

import static org.junit.Assert.assertEquals;
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;

import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;

public class HomeControllerTest {

	@Test
	public void testHomePage() throws Exception{
		HomeController controller = new HomeController();
		assertEquals("home", controller.home());
	}
	
	/**
	 * 
	 * 這裡需要注意一下standaloneSetup是靜态方法
	 * get("/") view() 抽象類中會有很多靜态方法,雖然
	 * 抽象不能new,但是方法可以建立對象
	 * @throws Exception
	 */
	@Test
	public void testHomePageRequest() throws Exception{
		HomeController controller = new HomeController();
		
		MockMvc mockMvc = 
				standaloneSetup(controller).build();
		mockMvc.perform(get("/homepage"))
		.andExpect(view().name("home"));
	}
}
           

總結:

1.第一個方法是簡單方法測試,第二個是模拟請求測試

2.注意standaloneSetup() 和 get() 以及view()都是靜态方法

3.其實你發現它,模拟操作過程,

MockMvcBuilders(設定)——》MockMvcRequestBuilders(請求)--》MockMvcResultMatchers(比對視圖)

寫個一個類模拟資料庫資料

首先接口:

package com.jack.data;

import java.util.List;

public interface SpittleRepository {
	List<Spittle> findSpittles(long max, int count);
}
           

  實作類

package com.jack.data.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Component;

import com.jack.data.Spittle;
import com.jack.data.SpittleRepository;

@Component
public class SpittleRepositoryImpl implements SpittleRepository{

	@Override
	public List<Spittle> findSpittles(long max, int count) {
		List<Spittle> list = new ArrayList<Spittle>();
		Spittle sp1 = new Spittle("第一個資訊", new Date(),100.00, 40.102);
		Spittle sp2 = new Spittle("第二個資訊", new Date());
		Spittle sp3 = new Spittle("第三個資訊", new Date());
		Spittle sp4 = new Spittle("第四個資訊", new Date());
		list.add(sp4);
		list.add(sp3);
		list.add(sp1);
		list.add(sp2);
		
		return list;
	}

}
           

控制類:

package com.jack.controller;

import java.util.List;
import java.util.Map;

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

import com.jack.data.Spittle;
import com.jack.data.SpittleRepository;

@Controller

@RequestMapping("/spittles")
public class SpittleController {
	
	private SpittleRepository spittleRepository;
	
	@Autowired
	public SpittleController(SpittleRepository spittleRepository){
		this.spittleRepository = spittleRepository;
	}
	
/*	@RequestMapping(method=RequestMethod.GET)
	public String spittles(Model model) {
		//将spittle添加到模型中
		//方式一
		//注意這裡沒有key,它可以根據List<Spittle> 推斷 key = spittleList
		model.addAttribute(
				spittleRepository.findSpittles(
						Long.MAX_VALUE, 20));
		
		//方式二
		//顯式指定key
		model.addAttribute("spittleList", spittleRepository.findSpittles(Long.MAX_VALUE, 20));
		
		
		
		//傳回視圖名
		return "spittles";
	}*/
	
	//方式三
	//它會根據請求/spittles,判斷 視圖為spittles
	/*@RequestMapping(method=RequestMethod.GET)
	public List<Spittle> spittles(){
		return spittleRepository.findSpittles(Long.MAX_VALUE, 20);
	}*/
	
	//方法四
	
	@RequestMapping(method=RequestMethod.GET)
	public String spittles(Map model){
		model.put("spittleList", 
				spittleRepository.findSpittles(Long.MAX_VALUE, 20));
		return "spittles";
	}
	
}
           

總結:

1.這麼多方法可以表示說明它有依據

2.依據請求路徑擷取視圖

3.根據傳回資料推斷key

4.model底層是Map資料格式

mock測試類

package com.jack.controller;

import static org.hamcrest.core.IsCollectionContaining.hasItems;
//這要引入新的mockito-all.jar
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.servlet.view.InternalResourceView;

import com.jack.data.Spittle;
import com.jack.data.SpittleRepository;
public class SpittleControllerTest {

	@Test
	public void shouldShowRecentSpittles() throws Exception{
		//建立模拟資料
		List<Spittle> expectedSpittles = createSpittleList(20);
		//模拟的類
		SpittleRepository mockRepository = 
				mock(SpittleRepository.class);
		//模拟類中的方法,隻要是調用findSpittles就傳回 expectedSpittles資料
		when(mockRepository.findSpittles(Long.MAX_VALUE, 20))
		.thenReturn(expectedSpittles);
		
		//往控制類注入資料類
		SpittleController controller = 
				new SpittleController(mockRepository);
		//設定模拟的controller
		MockMvc mockMvc = standaloneSetup(controller)
				.setSingleView( //表示不解析
						new InternalResourceView("/WEB-INF/views/spittles.jsp"))
				.build();
		//請求路徑/spittles
		mockMvc.perform(get("/spittles"))
			.andExpect(view().name("spittles")) //判斷視圖是否為spittles
			.andExpect(model().attributeExists("spittleList")) //是否存在這個屬性ID
			.andExpect(model().attribute("spittleList", 
					hasItems(expectedSpittles.toArray())));  //判斷資料是否一緻
				
	}
	
	private List<Spittle> createSpittleList(int count) {
		List<Spittle> spittleList = new ArrayList<Spittle>();
		for(int i=0; i< count; i++) {
			spittleList.add(new Spittle("Spittle" + i, new Date()));
			
		}
		return spittleList;
	}
}
           

總結:

1.引用包Mockito

2.發現測試模拟都是靜态類,不熟悉都不知道在哪個包下,很尴尬

import static org.hamcrest.core.IsCollectionContaining.hasItems;

//這要引入新的mockito-all.jar

import static org.mockito.Mockito.mock;

import static org.mockito.Mockito.when;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;

import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;

編寫spittles.jsp檔案

<%@ taglib	uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<%@ page language="java" import="java.util.*" 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>RecentSpittles</title>
<link rel="stylesheet" 
	type="text/css"
	href="<c:url value=" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" /resources/style.css"/>">
</head>
<body>
	<h1>Recent Spittles</h1>
	<c:forEach items="${spittleList }" var="spittle">
		<li id="spittle_<c:out value="spittle.id"/>">
			<div class="spittleMessage">
				<c:out value="${spittle.message}"></c:out>
			</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>
</body>
</html>
           

總結:

1、這裡要引用jstl-1.2.jar包

2、同時要添加這個一句話<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %>不然中文亂碼

3、當要用外部包的标簽的時候首先導入uri,設定字首prefix 例如 <%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %>

4、"" 裡面可以設定标簽能夠識别,例如:<li id="spittle_<c:out value="spittle.id"/>">

5、對于forEach items="${spittleList}" 周遊的屬性的key,而var="spittle"周遊處理的單個對象,注意${}是指在引号内

6、對于對象的屬性直接可以用對象.屬性的來擷取值

7、對于jsp輸出标簽為<c:out value="輸入内容"/>

效果為:

第5章 建構Spring Web 應用程式 --筆記1

5.2 接受請求的輸入

傳入的方式:

  • 查詢參數(Query Paramter)
  • 表單參數(Form Parameter)
  • 路徑變量(Path Variable)

5.2.1處理查詢參數

測試類:

@Test 
	public void shouldShowPagedSpittles() throws Exception {
		List<Spittle> expectedSpittles = createSpittleList(50);
		SpittleRepository mockRepository = mock(SpittleRepository.class);
		when(mockRepository.findSpittles(238900, 50))
		.thenReturn(expectedSpittles);
		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(expectedSpittles.toArray())));
	}
           

總結:在路徑後面 加上 ?+鍵值對 + 連接配接符(&)+鍵值對 例如  /spittles?max=238900&count=50

Controller類:

package com.jack.controller;

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 org.springframework.web.bind.annotation.RequestParam;

import com.jack.data.SpittleRepository;

@Controller

@RequestMapping("/spittles")
public class SpittleController {
	
	private SpittleRepository spittleRepository;
	private static final String MAX_LONG_AS_STRING = Long.MAX_VALUE+"";
	@Autowired
	public SpittleController(SpittleRepository spittleRepository){
		this.spittleRepository = spittleRepository;
	}
	
	@RequestMapping(method=RequestMethod.GET)
	//@RequestParam("max") long max,@RequestParam("count") int count
	public String spittles(Model model, @RequestParam(value="max", defaultValue=MAX_LONG_AS_STRING) long max,
			@RequestParam(value="count", defaultValue="20") int count) {
		
		//注意這裡沒有key,它可以根據List<Spittle> 推斷 key = spittleList
		model.addAttribute(
				spittleRepository.findSpittles(
						max, count));
		
		//傳回視圖名
		return "spittles";
	}
	
	
	
	
}
           

總結:用注解 @RequestParam,可以指定預設值, defaultValue ,注意defaultValue是字元串,是以先轉成字元串,再轉成目标類型

5.1.2.路徑傳值:

測試方法:

@Test
	public void testSpitte() throws Exception{
		Spittle expectedSpittle = new Spittle("Hello", new Date());
		SpittleRepository mockRepository = mock(SpittleRepository.class);
		when (mockRepository.findOne(123456)).thenReturn(expectedSpittle);
		
		SpittleController controller = new SpittleController(mockRepository);
		
		MockMvc mockMvc = standaloneSetup(controller).build();
		
		mockMvc.perform(get("/spittles/123456"))
			.andExpect(view().name("spittle"))
			.andExpect(model().attributeExists("spittle"))
			.andExpect(model().attribute("spittle", expectedSpittle));
	}
           

控制類的方法

@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)
	public String spittle(@PathVariable("spittleId") long spittleId,
			Model model){
		model.addAttribute(spittleRepository.findOne(spittleId));
		return "spittle";
	}
           

spittle.jsp

<%@ taglib	uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<%@ page language="java" import="java.util.*" 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>RecentSpittles</title>
<link rel="stylesheet" 
	type="text/css"
	href="<c:url value=" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" /resources/style.css"/>">
</head>
<body>
	<h1>Recent Spittle</h1>
	<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>
           

SpittleRepository.java 接口增加方法

Spittle findOne(long i);

SpittleRepositoryImpl.java 實作接口方法

@Override
	public Spittle findOne(long i) {
		
		return new Spittle("第一個微網誌" , new Date(), 100.0,100.0);
	}
           

結果:

第5章 建構Spring Web 應用程式 --筆記1

5.1.3.表單傳遞資料

測試類:

package com.jack.controller;

//這要引入新的mockito-all.jar
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;

import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;

import com.jack.data.Spitter;
import com.jack.data.SpitterRepository;
public class SpittlerControllerTest {
	
	@Test
	public void shouldShowRegistration() throws Exception{
		SpittlerController controller = new SpittlerController();
		MockMvc mockMvc = standaloneSetup(controller).build();
		mockMvc.perform(get("/spittler/register"))
			.andExpect(view().name("registerForm"));
	}
	
	@Test 
	public void shouldProcessRegistration() throws Exception {
		SpitterRepository mockRepository = 
				mock(SpitterRepository.class); 
		Spitter unsaved =
				new Spitter("Jack", "Bauer", "jbauer", "24hours");
		Spitter saved = 
				new Spitter(24L,"Jack", "Bauer", "jbauer", "24hours");
		when(mockRepository.save(unsaved)).thenReturn(saved);
		
		SpittlerController controller =
				new SpittlerController(mockRepository);
		MockMvc mockMvc = standaloneSetup(controller).build();
		
		mockMvc.perform(post("/spitter/register")
				.param("firstName", "Jack")
				.param("lastName", "Bauer")
				.param("username", "jbauer")
				.param("password", "24hours"))
				.andExpect(redirectedUrl("/spitter/jbauer"));
		verify(mockRepository, atLeastOnce()).save(unsaved); //校驗儲存情況
			
			
	}
}
           

總結:

1、總會發現老外首先寫的測試類,然後才是寫代碼,測試驅動,可以學習一下

2、注冊過程是,首先顯示一個表單頁(registerForm.jsp)——》處理表單請求控制器("/spitter/register")--》簡短的呈現頁 (profile.jsp)

3、測試類差不多就是靜态方法,鍊式方法

4、redirectedUrl("/spitter/jbauer") 重定向防止重複送出

5、verify驗證repository儲存方法,是否正确

控制類

package com.jack.controller;

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 com.jack.data.Spitter;
import com.jack.data.SpitterRepository;

@Controller

@RequestMapping("/spitter")
public class SpittlerController {
	
	private SpitterRepository spitterRepository;
	public SpittlerController(){}
	@Autowired 
	public SpittlerController(SpitterRepository spitterRepository){
		this.spitterRepository = spitterRepository;
	}
	@RequestMapping(value = "/register", method=RequestMethod.GET)
	public String showRegistrationForm(){
		return "registerForm";
	}
	
	@RequestMapping(value="/register", method=RequestMethod.POST)
	public String processRegistration(Spitter spitter){
		spitterRepository.save(spitter);
		
		return "redirect:/spitter/" + spitter.getUsername();
	}
	
	@RequestMapping(value="/{username}", method=RequestMethod.GET)
	public String showSpitterProfile(
			@PathVariable String username, Model model){
		Spitter spitter = spitterRepository.findByUsername(username);
		model.addAttribute(spitter);
		
		return "profile";
	}
}
           

總結:

1、雖然請求路徑一樣,請求方式不一樣 ,例如兩個register

2、redirect:/spitter/ 重定向方法

3、最後傳回視圖profile

package com.jack.data;

public interface SpitterRepository {

	Spitter save(Spitter spitter);

	Spitter findByUsername(String username);

}
           
package com.jack.data.impl;

import org.springframework.stereotype.Component;

import com.jack.data.Spitter;
import com.jack.data.SpitterRepository;

@Component
public class SpitterRepositoryImpl implements SpitterRepository{

	@Override
	public Spitter save(Spitter spitter) {
		System.out.println("儲存成功");
		return null;
	}

	@Override
	public Spitter findByUsername(String username) {
		Spitter spitter =
				new Spitter("Jack", "Bauer", "jbauer", "24hours");
		return spitter;
	}

}
           

總結:這裡沒有具體實作資料庫互動

實體類:

package com.jack.data;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

public class Spitter {

	private long l;
	private String firstName;
	private String lastName;
	private String username;
	private String password;
	
	public Spitter() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Spitter(String firstName, String lastName, String username, String password) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.username = username;
		this.password = password;
	}
	public Spitter(long l, String firstName, String lastName, String username, String password) {
		this.l = l;
		this.firstName = firstName;
		this.lastName = lastName;
		this.username = username;
		this.password = password;
	}
	public String getFirstName() {
		return firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public String getUsername() {
		return username;
	}
	public String getPassword() {
		return password;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public long getL() {
		return l;
	}
	public void setL(long l) {
		this.l = l;
	}
	
	@Override
	public boolean equals(Object obj) {
		
		return EqualsBuilder.reflectionEquals(this, obj, "firstName", "lastName");
	}
	@Override
	public int hashCode() {
		
		return HashCodeBuilder.reflectionHashCode(this, "firstName", "lastName");
	}
	@Override
	public String toString() {
		return "Spitter [l=" + l + ", firstName=" + firstName + ", lastName=" + lastName + ", username=" + username
				+ ", password=" + password + "]";
	}
	
	
	
}
           

profile.jsp

<%@ taglib	uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<!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>Spittr</title>
<link rel="stylesheet" 
	type="text/css"
	href="<c:url value=" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" /resources/style.css"/>">
</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>
           

registerForm.jsp

<%@ taglib	uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<%@ page language="java" import="java.util.*" 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>RegisterPage</title>
<link rel="stylesheet" 
	type="text/css"
	href="<c:url value=" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" /resources/style.css"/>">
</head>
<body>
	<h1>注冊</h1>
	<form action="" 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" />
	</form>
</body>
</html>
           

5.3校驗表單

Spring 校驗 Java Validation API 又稱 JSR-303 Hibernate Validator Java校驗API javax.validation.constraints包下

  • @AssertFalse   所注解的元素必須是Boolean類型,并且值為false
  • @AssertTrue   所有注解的元素必須是Boolean類型, 并且值為true
  • @DecimalMax 所有注解的元素必須是數字,并且它的值要小于或等于給定的BigDecimalString值
  • @DecimalMin 所注解的元素必須是數字,并且它的值要大于或者等于給定的BigDecimalString值
  • @Digits 所注解的元素必須是數字,并且它的值必須指定位數
  • @Future 所注解的元素的值必須是一個将來的日期
  • @Max 所注解的元素必須是數字,并且它的值要小于或等于給定的值
  • @Min 所注解的元素必須是數字,并且它的值要大于或等于給定的值
  • @NotNull 所注解元素的值必須不能為null
  • @Null 所注解元素的值必須為null
  • @Past 所注解的元素的值必須是一個已過去的日期
  • @Pattern 所注解的元素的值必須比對給定的正規表達式
  • @Size 所注解的元素的值必須是String、集合或數組,并且它的長度要符合給定的範圍

引入jar

<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->

<dependency>

    <groupId>javax.validation</groupId>

    <artifactId>validation-api</artifactId>

    <version>1.1.0.Final</version>

</dependency>

<dependency>

    <groupId>org.hibernate</groupId>

    <artifactId>hibernate-validator</artifactId>

    <version>5.4.1.Final</version>

</dependency>

修改Spitter.java

        @NotNull

@Size(min=2, max=30)

private String firstName;

@NotNull

@Size(min=2, max=30)

private String lastName;

@NotNull

@Size(min=5, max=16)

private String username;

@NotNull

@Size(min=5, max=25)

private String password;

修改控制類

//不滿足要求自動跳轉表單頁

@RequestMapping(value="/register", method=RequestMethod.POST)

public String processRegistration( @Valid Spitter spitter,

Errors errors){

if(errors.hasErrors()) {

return "registerForm";

}

spitterRepository.save(spitter);

return "redirect:/spitter/" + spitter.getUsername();

}

總結:影響最深就是先寫測試類,然後寫代碼。測試驅動

用例Demo

點選打開連結

繼續閱讀