springmvc踩坑-控制器中的根目录与路径映射

在springmvc中,@RequestMapping的值可以/xxx,也可以是xxx,效果一样

@RequestMapping(value="/emp/{id}",method=RequestMethod.DELETE)

特别注意一下,在rest风格中 请求页面如果是 “emp/${emp.id} ,那么处理器的RequestMapping值也要是 /emp/{id} 不用写错成 /emp 导致无法访问

另一方面:控制器的返回值 return “redirect:/emps”; 指明重定向和转发的都要用用绝对路径,否则路径解析就出错了。

springmvc运算-基础练手项目(3)-删除操作

springmvc错误心得:请求路径问题

1、浏览器地址栏:域名(也叫根目录)/文件目录/a.jsp
如果:网页中超链接

<a href="/emp/${emp.id}">Delete</a>

则浏览器跳转地址:   域名(也叫根目录)/emp/数字id

如果:网站中超链接

<a href="emp/${emp.id}">Delete</a>

则浏览器跳转地址:  域名(也叫根目录)/文件目录/emp/数字id
=============================================
相对路径:是相对当前浏览器路径来说的。
如果浏览器地址:根目录/abc/1005 页面中 超链接是
<a href=”abc/1008″>scan</a>
点击超链接的结果是:根目录/abc/abc/1008       [这个需要注意啦]

关于:
request.getContextPath()得到的是   项目所在目录   :
如果项目为根目录,则得到一个””,即空的字条串【在浏览器看来:等价于-> 域名】
如果项目名为dzjc,将得到/dzjc 【在浏览器看来等价于 ->域名/dzjc】

比如下面的超链接:如果网站名不在根目录(也就是不等于域名),比如在/dzjc(也就是域名/dzjc)
<a href="${pageContext.request.contextPath }/emp">hh</a>
效果等价于 <a href="/dzjc/emp" >hh</a>

<a href=”XXX.jsp”> 应该就是指当前路径下的这个xxx.jsp页面,有时候也可以在head里设置html:base来解决路径的问题,不过用的最多的还是request.getContextPath。

用EL来表示相同功能的EL为:${pageContext.request.getContextPath()}
=============================================
2、服务端控制器中:

在springmvc中,@RequestMapping的值可以/xxx,也可以是xxx,效果一样

@RequestMapping(value="/emp/{id}",method=RequestMethod.DELETE)

特别注意一下,在rest风格中 请求页面如果是 “emp/${emp.id}  ,那么处理器的RequestMapping值也要是 /emp/{id}   不要写错成 /emp 导致无法访问

另一方面:控制器的返回值   return “redirect:/emps”; 指明重定向和转发的都要用用绝对路径,否则路径解析就出错了。


一、配置文件

web.xml 配置文件和查询所有雇员信息的配置相同。
springmvc.xml配置文件,因为需要请求静态资源(加载js文件),然后利用js发送post请求。
所以要在 springmvc.xml【即转发配置器】中,添加请求静态资源的代码:

   <!--  
		default-servlet-handler 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,
		它会对进入 DispatcherServlet 的请求进行筛查, 如果发现是没有经过映射的请求, 就将该请求交由 WEB 应用服务器默认的 
		Servlet 处理. 如果不是静态资源的请求,才由 DispatcherServlet 继续处理

		一般 WEB 应用服务器默认的 Servlet 的名称都是 default.
		若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定
		
	-->
	<mvc:default-servlet-handler/>
	<!-- 前面的 mvc:default-servlet-handler 可以解决静态资源了,但是让其他经过handler的请求,又失效了,所以配置了下面的 mvc:annotation-driven 来解决问题 -->
	<mvc:annotation-driven></mvc:annotation-driven>	

已经在springmvc基础-配置开发环境中提到过了。

二、请求测试页

第一步,跳转到待删除页
其实就是/emps请求,跳转到showGetEmps.jsp

第二步,在showGetEmps.jsp页面中配置   删除模块的超链接。

<td><a class="delete" href="emp/${emp.id}">Delete</a></td>

因为是删除方法,必须要提供post方法传递。所以需要js,而加载js属于请求静态资源。所以上文介绍了如何编辑配置文件,用来支持加载静态资源。

第三步,在showGetEmps.jsp页面中配置  form表单。

<body>
    <form action="" method="POST">
       <input type="hidden" name="_method" value="DELETE"/>
    </form>
  ...
</body>

第四步,在showGetEmps.jsp页面中,用js控制 删除的超链接以post方式发送。

<!--  
	SpringMVC 处理静态资源:
	1. 为什么会有这样的问题:
	优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀
	若将 DispatcherServlet 请求映射配置为 /, 
	则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, 
        SpringMVC 会将他们当成一个普通请求处理, 因找不到对应处理器将导致错误。
	2. 解决: 在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/>
-->
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
	$(function(){
		alert("hello jquery");
		$(".delete").click(function(){
			var href = $(this).attr("href");
			$("form").attr("action", href).submit();
			return false;
		});
	})
</script>

三、结果响应页

还是返回showGetEmps.jsp页面

四、编辑控制器

//在所有雇员信息页,进行删除雇员操作 //跳转部分不需要了,本身就是跳转到显示有雇员信息页
@RequestMapping(value="/emp/{id}",method=RequestMethod.DELETE)
public String deleteEmp(@PathVariable("id") Integer id){
        employeeDao.delete(id);	
        System.out.println("hello delete");
	return "redirect:/emps";
}

 

springmvc运算-基础练手项目(2)-添加操作

一、配置文件

web.xml,springmvc.xml,这些配置文件和查询所有雇员信息的配置相同。

二、请求测试页面

第一步,跳转到添加雇员信息页
浏览器访问链接: http://localhost:8080/springmvc-2/doGetEmps
或者网页中,插入超链接:

<body>
<a href="doAddEmp">转到雇员信息页</a>
</body>

第二步,显示添加雇员信息页

addEmp.jsp

<%@ page import="java.util.HashMap"%>
<%@ page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!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>

	<!--  
		1. WHY 使用 form 标签呢 ?
		可以更快速的开发出表单页面, 而且可以更方便的进行表单值的回显
		2. 注意:
		可以通过 modelAttribute 属性指定绑定的模型属性,
		若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean
		如果该属性值也不存在,则会发生错误。
		
		大白话:form:form 表单标签,在springmvc中是一定要回显的,哪怕是第一次也要支持回显。
		所以第一次请求时,form:form 表单标签会从 request域中的 关键字中查找 默认值是command(如果 form:form标签 指定modelAttribute="XXX",则按照XXX关键字来)  查看属性值,用来填充表单值。
	
	-->

	<form:form action="emp" method="post" modelAttribute="employee">
		<!-- path标签对应 html表单标签的 name属性值,支持级联 如 path="department.id" -->
       LastName:<form:input path="lastName"  />
		<br>
       Email:<form:input path="email" />
		<%
			Map<String, String> genders = new HashMap();
				genders.put("1", "Male");
				genders.put("0", "Female");
				request.setAttribute("genders", genders);
		%>
		<br>
     Gender:<form:radiobuttons path="gender" items="${genders}" />
     <br>
     Department:<form:select path="department.id" items="${departments}" itemLabel="departmentName" itemValue="id"></form:select>
     <br>
		<input type="submit" value="submit" />
	</form:form>

</body>
</html>

总结:addEmp.jsp中用了表单标签,而springmvc中需要表单标签回显值,默认从request中查找command属性,匹配表单值。当然如果,表单标签有@ModelAttribute,就按照@ModelAttribute指定的属性值,优先查找并匹配表单值。如果没有匹配值,就报错了。

三、编辑控制器

在查询所有雇员的信息的控制器的基础上,添加:

	//跳转到添加雇员信息页面
    @RequestMapping("/doAddEmp")
	public String doAddEmp(Map<String, Object> map){
    	//为了提供在添加页面,部门列表
    	map.put("departments",departmentDao.getDepartments());
    	//为了提供雇员信息的回显值,添加一个空的雇员信息
    	map.put("employee", new Employee());
    	return "addEmp";
    }
	
    //处理添加雇员请求,并重定向到 	@RequestMapping("/emps")
    @RequestMapping(value="/emp", method=RequestMethod.POST)
    public String addEmp(Employee employee) {
    	employeeDao.save(employee);
    	return "redirect:/emps";
		
	}

四、请求结果响应页

重定向到了 showGetEmps.jsp

 

 

springmvc运算-基础练手项目(1)-查询操作

1、编辑web.xml ,常规配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<filter>
		<filter-name>HiddenHttpMethodFilter</filter-name>
		<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>HiddenHttpMethodFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<servlet>
		<servlet-name>dispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
			<!-- 配置 DispatcherServlet 的一个初始化参数: 配置 SpringMVC 配置文件的位置和名称 -->
		<!-- 
			实际上也可以不通过 contextConfigLocation 来配置 SpringMVC 的配置文件, 而使用默认的.
			默认的配置文件为: /WEB-INF/<servlet-name>-servlet.xml
		-->

		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc.xml</param-value>
		</init-param>
	
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>dispatcherServlet</servlet-name>
		<!-- 
               第一种:*.action 或者 *.do,访问以.action或*.do结尾 由DispatcherServlet进行解析
               第二种:/,所以访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析
               使用此种方式可以实现 RESTful风格的url
               第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时,
               仍然会由DispatcherServlet解析jsp地址,不能根据jsp页面找到handler,会报错。
        -->
		<url-pattern>/</url-pattern>
	</servlet-mapping>
</web-app>

2、编辑转发配置文件(springmvc.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

	<!-- 配置自动扫描的包 -->
	<context:component-scan base-package="com.test.springmvc"></context:component-scan>

	<!-- 配置视图解析器 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/views/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>

</beans>

3、测试页面

第一步:请求控制器返回查询页面:
浏览器访问链接: http://localhost:8080/springmvc-2/doGetEmps
或者在页面中配置超链接

<body>
<a href="doGetEmps">请求所有雇员信息页面</a>
</body>

第二步:在查询页面中配置了超链接,请求控制器返回查询后的结果
查询页:getEmps.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/fmt" %>

<!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>

<a href="emps">请求所有雇员信息(超链接属于get请求)</a>

</body>
</html>

本质上,只要一步直接请求好了,但是为了后续增删改的统一,所以拆成2步。

4、结果响应页面

showGetEmps.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!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>Get All</title>
</head>
<body>

	<c:if test="${empty requestScope.employees}">
没有任何员工信息
</c:if>
	<c:if test="${ !empty requestScope.employees }">
		<table border="1" cellpadding="10" cellspacing="0">
			<tr>
				<th>ID</th>
				<th>LastName</th>
				<th>Email</th>
				<th>Gender</th>
				<th>Department</th>
				<th>Edit</th>
				<th>Delete</th>
			</tr>

			<c:forEach items="${requestScope.employees }" var="emp">
			<tr>
			<td>${emp.id}</td>
            <td>${emp.lastName}</td>
            <td>${emp.email}</td>	            
			<td>${emp.gender==0? "Female":"Male"}</td>					
			<td>${emp.department.departmentName}</td>			
			<td><a href="">Edit</a></td>
			<td><a href="">Delete</a></td>			
			</tr>
			</c:forEach>
		</table>
	</c:if>

</body>
</html>

5、编辑控制器

package com.test.springmvc.crud.handlers;

import java.util.Map;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
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.test.springmvc.crud.dao.DepartmentDao;
import com.test.springmvc.crud.dao.EmployeeDao;
import com.test.springmvc.crud.entities.Employee;



@Controller
public class EmployeeHandler {

	@Autowired
	private EmployeeDao employeeDao;
	
	@Autowired
	private DepartmentDao departmentDao;

	
	//跳转到查看所有雇员信息页
        @RequestMapping("/doGetEmps")
	public String doGetEmps(){
    	return "getEmps";
    }
    
	//查看所有雇员信息,采用默认的get方法,属于crud操作
	@RequestMapping("/emps")
	public String getEmps(Map<String, Object> map){
		map.put("employees", employeeDao.getAll());
		return "showGetEmps";
	}

	
}

6、数据源配置

(1)entity

Employee.java

package com.test.springmvc.crud.entities;

import java.util.Date;

import javax.validation.constraints.Past;

import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;

public class Employee {

	private Integer id;
	
	private String lastName;

	private String email;
	//1 male, 0 female
	private Integer gender;
	
	private Department department;
	

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	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;
	}

	public Integer getGender() {
		return gender;
	}

	public void setGender(Integer gender) {
		this.gender = gender;
	}

	public Department getDepartment() {
		return department;
	}

	public void setDepartment(Department department) {
		this.department = department;
	}

	
	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email="
				+ email + ", gender=" + gender + ", department=" + department
				+ "]";
	}

	public Employee(Integer id, String lastName, String email, Integer gender,
			Department department) {
		super();
		this.id = id;
		this.lastName = lastName;
		this.email = email;
		this.gender = gender;
		this.department = department;
	}

	public Employee() {
		// TODO Auto-generated constructor stub
	}
}

Department.java

package com.test.springmvc.crud.entities;

public class Department {

	private Integer id;
	private String departmentName;

	public Department() {
		// TODO Auto-generated constructor stub
	}
	
	public Department(int i, String string) {
		this.id = i;
		this.departmentName = string;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getDepartmentName() {
		return departmentName;
	}

	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}

	@Override
	public String toString() {
		return "Department [id=" + id + ", departmentName=" + departmentName
				+ "]";
	}
	
}

(2)Dao

package com.test.springmvc.crud.dao;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.test.springmvc.crud.entities.Department;
import com.test.springmvc.crud.entities.Employee;


@Repository
public class EmployeeDao {

	private static Map<Integer, Employee> employees = null;
	
	@Autowired
	private DepartmentDao departmentDao;
	
	static{
		employees = new HashMap<Integer, Employee>();

		employees.put(1001, new Employee(1001, "E-AA", "[email protected]", 1, new Department(101, "D-AA")));
		employees.put(1002, new Employee(1002, "E-BB", "[email protected]", 1, new Department(102, "D-BB")));
		employees.put(1003, new Employee(1003, "E-CC", "[email protected]", 0, new Department(103, "D-CC")));
		employees.put(1004, new Employee(1004, "E-DD", "[email protected]", 0, new Department(104, "D-DD")));
		employees.put(1005, new Employee(1005, "E-EE", "[email protected]", 1, new Department(105, "D-EE")));
	}
	
	private static Integer initId = 1006;
	
	public void save(Employee employee){
		if(employee.getId() == null){
			employee.setId(initId++);
		}
		
		employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
		employees.put(employee.getId(), employee);
	}
	
	public Collection<Employee> getAll(){
		return employees.values();
	}
	
	public Employee get(Integer id){
		return employees.get(id);
	}
	
	public void delete(Integer id){
		employees.remove(id);
	}
}
package com.test.springmvc.crud.dao;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Repository;

import com.test.springmvc.crud.entities.Department;


@Repository
public class DepartmentDao {

	private static Map<Integer, Department> departments = null;
	
	static{
		departments = new HashMap<Integer, Department>();
		
		departments.put(101, new Department(101, "D-AA"));
		departments.put(102, new Department(102, "D-BB"));
		departments.put(103, new Department(103, "D-CC"));
		departments.put(104, new Department(104, "D-DD"));
		departments.put(105, new Department(105, "D-EE"));
	}
	
	public Collection<Department> getDepartments(){
		return departments.values();
	}
	
	public Department getDepartment(Integer id){
		return departments.get(id);
	}
	
}

 

springmvc运算-基础练手项目-概述

为了掌握springmvc的增删改查操作,进行的练手项目。

1、查询操作(Get)

2、添加操作(Post)

3、删除操作(Delete)

4、更新操作(Put)

总结:做各个功能模块时,应该都统一,方便以后的理解和维护。虽然可能会造成一定的冗余,但是总体上还是不错的。

在这个项目:分成两步请求了。第一步,请求控制器跳转到相应的增删改查页面。第二步,在增删改查页面中,又一次请求控制器,然后返回结果。

springmvc基础-@ModelAttribute注解详解

@ModelAttribute  三种用法

1、对handler中的方法进行注解:

@ModelAttribute 注解的方法,本质来说:会在其他方法执行前,会首先被调用。用于初始化一些参数。然后其他方法执行时,会先查找这些参数是否已经存在,若不存则创建一个。

参看:springmvc基础-控制器返回值总结

2、对handler内的方法的形参进行注解:

html表单提交的,可以在控制器内生产一个pojo对象。默认情况下:会将该pojo对象的类型的首字母小写作为关键字,将pojo对象值 作为参数。放置到request属性中。如果pojo对象前面有@ModelAttribute(value =”XXX”),则request存储的pojo对象关键字为XXX,不再是该对象的类型的首字母小写。

参看:springmvc基础-请求映射总结

3、在jsp中的使用springmvc 的表单标签 问题:

参数页面:

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>

<body>

       <!--  
		1. WHY 使用 form 标签呢 ?
		可以更快速的开发出表单页面, 而且可以更方便的进行表单值的回显
		2. 注意:
		可以通过 modelAttribute 属性指定绑定的模型属性,
		若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean
		如果该属性值也不存在,则会发生错误。
	-->

        <form:form action="emp" method="post" modelAttribute="employee">
		<!-- path标签对应 html表单标签的 name属性值 -->
                LastName:<form:input path="lastName"  />

		<input type="submit" value="submit" />
	</form:form>

       <!-- form:form 标签在springmvc会有回显值,一开始加载页面时,就需要填充表单,
       所以 modelAttribute="employee" 用来标记从 request中的 取出 employee 关键字的 属性值 -->

</body>

编辑处理器:

@RequestMapping(value="/emp", method=RequestMethod.GET)
	public String input(Map<String, Object> map){

	    //主要是每次 访问表单时,springmvc 都会 回显 之前的表单值,因为第一次 没有创建,所以需要默认新建一个
		map.put("employee", new Employee());
		return "input";
	}

 

springmvc基础-视图与视图解析器详解

一、概述

  • 请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的 处理方法,Spring MVC 也会在内部将它们装配成一个ModelAndView 对象,它包含了逻辑名和模型对象的视图。
  • Spring MVC 借助视图解析器(ViewResolver)得到最终 的视图对象(View),最终的视图可以是 JSP ,也可能是Excel、JFreeChart  等各种表现形式的视图。
  • 对于最终究竟采取何种视图对象对模型数据进行渲染,处 理器并不关心,处理器工作重点聚焦在生产模型数据的工 作上,从而实现 MVC 的充分解耦。

二、视图含义

  • 视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客 户。
  • 为了实现视图模型和具体实现技术的解耦,Spring 在org.springframework.web.servlet 包中定义了一个高度抽象的 View接口:

  • 视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题

三、常用的视图实现类

四、视图解析器

  • SpringMVC 为逻辑视图名的解析提供了不同的策略,可 以在 Spring WEB 上下文中配置一种或多种解析策略,并 指定他们之间的先后顺序。每一种映射策略对应一个具体 的视图解析器实现类。
  • 视图解析器的作用比较单一:将逻辑视图解析为一个具体 的视图对象。
  • 所有的视图解析器都必须实现 ViewResolver 接口:

五、常用的视图解析器实现类

  • 程序员可以选择一种视图解析器或混用多种视图解析器
  • 每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可 以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。
  • SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常

六、自定义视图

大白话总结:1、编辑正常的请求连接提交给控制器。2、控制器处理请求 返回视图名。3、视图解析器  利用视图名   从IOC容器中 获取 自定义视图。

比如 控制器返回”success”,

如果配置用InternalResourceViewResolver解析的视图,肯定有解析器的前缀和后缀,可能最终解析完路径是 /WEB-INF/views/success.jsp
[即实际地址是:网站根目录/WEB-INF/views/success.jsp]
因为如果不想用 解析器的前缀和后缀 ,那么控制器的返回值应该是 WEB-INF/views/success.jsp
补充:控制器返回字符串值 “/WEB-INF/views/success.jsp” 和这个效果一样 “WEB-INF/views/success.jsp”

如果配置用BeanNameViewResolver视图解析器,则会根据视图名去IOC容器里面,获取一个视图。

1、编辑测试页

在测试页面添加超链接

<body>
测试自定义view
<a href="testredirect">testdiyview</a>
</body>

2、编辑控制器

@RequestMapping("/diyview")
public String testdiyview(){
		
	System.out.println("test-diyview");
	//返回值是自定义视图的类名且第一个字母需小写
        return "helloView";
}

3、编辑转发配置页

<!-- 配置视图  BeanNameViewResolver 解析器: 使用视图的名字来解析视图 -->
<!-- 通过 order 属性来定义视图解析器的优先级, order 值越小优先级越高 , 至于InternalResourceViewResolver其优先级是最低的 -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
    <property name="order" value="100"></property>
</bean>

核心注意:当时在转发配置页中:扫描注解包时,扫描路径是
com.test.springmvc.handlers 所以com.test.springmvc.views 无法扫描到【views包下面有view类,里面有注解】所以正确做法是:

<!-- 对于注解的Handler可以单个配置 实际开发中建议使用组件扫描 -->
<!-- <bean class="com.test.springmvc.handlers.HelloWorld" />  -->
<!-- 可以扫描controller、service、...这里让扫描controller,指定controller的包,但是view的包下面的注解类就扫描不到了,
所以 com.test.springmvc.handlers 改成 com.test.springmvc就行啦,子目录都能扫描得到  -->
<!--下面是 配置扫描  指定目录包 中的 java文件 -->
<context:component-scan base-package="com.test.springmvc"></context:component-scan>

4、创建自定义view

package com.test.springmvc.views;

import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.servlet.View;

//这个@Component注解的意思是  将该view 放到 IOC 容器里面 
@Component
public class HelloView implements View {

	@Override
	public String getContentType() {
		// TODO Auto-generated method stub
		return "text/html";
	}

	@Override
	public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		// TODO Auto-generated method stub
		response.getWriter().print("hello view ,time" + new Date());
	}

}

 

springmvc基础-控制器返回值总结

关于请求问题:
请求映射到了控制器,如果控制器处理后的返回值是 “success” ,经过解析器转换成 WEB-INF/views/success.jsp 【如果解析器没有前后缀,则控制器的返回值就必须是完整的,也就是带上了前后缀的】
最后的完整路径是 :网站根目录/WEB-INF/views/success.jsp
【当然,因为/WEB-INF 文件夹仅对服务器可见,对浏览器隐藏的,所以直接访问网站根目录/WEB-INF/views/success.jsp  是无法访问的】

springmvc的控制器【controller】或者叫Handler,它的返回值是:ModelAndView 类型。之前学习过说返回值可以是map或string。其实到最后,都会内部转化成ModelAndView 类型。

一、基础流程

测试: <a href=”springmvc/testModelAndView”>Test ModelAndView</a>

控制器:

/**
	 * 目标方法的返回值可以是 ModelAndView 类型。 
	 * 其中可以包含视图和模型信息
	 * SpringMVC 会把 ModelAndView 的 model 中数据放入到 request 域对象中. 
	 * @return
	 */
	@RequestMapping("/testModelAndView")
	public ModelAndView testModelAndView(){
		String viewName = SUCCESS;
		ModelAndView modelAndView = new ModelAndView(viewName);
		
		//添加模型数据到 ModelAndView 中.
		modelAndView.addObject("time", new Date());
		
		return modelAndView;
	}

控制器中 ModelAndView 的构造函数名,就是ModelAndView中的view里面的转发页面的名字。

返回页jsp编辑:
time: ${requestScope.time }

二、控制器中的map参数

控制器中的map参数,最后变成了返回值 ModelAndView 中的model。至于ModelAndView 中的view里面包含了返回页的名字。

测试: <a href=”springmvc/testMap”>Test Map</a>

控制器:

      /**
	 * 目标方法可以添加 Map 类型(实际上也可以是 Model 类型或 ModelMap 类型)的参数. 【因为是继承关系,最后都是一样的】
	 * @param map
	 * @return
	 */
	@RequestMapping("/testMap")
	public String testMap(Map<String, Object> map){
		System.out.println(map.getClass().getName()); 
		map.put("names", Arrays.asList("Tom", "Jerry", "Mike"));
		return "success";
	}

返回页jsp编辑:

names: ${requestScope.names }

三、控制器中的@SessionAttributes

@SessionAttributes : 该注解只能放在类的上面. 而不能修饰放方法. 

测试:<a href=”springmvc/testSessionAttributes”>Test SessionAttributes</a>

控制器:

@SessionAttributes(value={"user"}, types={String.class})
@RequestMapping("/springmvc")
@Controller
public class SpringMVCTest {

      /**
	 * @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外(实际上使用的是 value 属性值),
	 * 还可以通过模型属性的对象类型指定哪些模型属性需要放到会话中(实际上使用的是 types 属性值)
	 * 
	 * 注意: 该注解只能放在类的上面. 而不能修饰放方法. 
	 */
	@RequestMapping("/testSessionAttributes")
	public String testSessionAttributes(Map<String, Object> map){
		User user = new User("Tom", "123456", "[email protected]", 15);
		map.put("user", user);
		map.put("school", "atguigu");
		return "success";
	}

}

这个实验表示:加了@SessionAttributes 注解后,map会根据相应的关键字或类型名,额外放置一份数据到session中。原本map放置到request中的信息,仍会保留在request中。

返回值jsp页:

	request user: ${requestScope.user }
	<br><br>
	
	session user: ${sessionScope.user }
	<br><br>
	
	request school: ${requestScope.school }
	<br><br>
	
	session school: ${sessionScope.school }

四、控制器中的@ModelAttribute

@ModelAttribute 注解的方法,本质来说:会在其他方法执行前,会首先被调用。用于初始化一些参数。然后其他方法执行时,会先查找这些参数是否已经存在,若不存则创建一个。

这个例子:介绍的是从数据库中读取一段信息,然后修改了一部分,又重新保存到数据库中。
测试页:

<!--  
		模拟修改操作
		1. 原始数据为: 1, Tom, 123456,[email protected],12
		2. 密码不能被修改.
		3. 表单回显, 模拟操作直接在表单填写对应的属性值
	-->
	<form action="springmvc/testModelAttribute" method="Post">
		<input type="hidden" name="id" value="1"/>
		username: <input type="text" name="username" value="Tom"/>
		<br>
		email: <input type="text" name="email" value="[email protected]"/>
		<br>
		age: <input type="text" name="age" value="12"/>
		<br>
		<input type="submit" value="Submit"/>
	</form>

控制器:

       /**
	 * 1. 有 @ModelAttribute 标记的方法, 会在每个目标方法执行之前被 SpringMVC 调用! 
	 * 2. @ModelAttribute 注解也可以来修饰目标方法 POJO 类型的入参, 其 value 属性值有如下的作用:
	 * 1). SpringMVC 会使用 value 属性值在 implicitModel 中查找对应的对象, 若存在则会直接传入到目标方法的入参中.
	 * 2). SpringMVC 会一 value 为 key, POJO 类型的对象为 value, 存入到 request 中. 
	 */
	@ModelAttribute
	public void getUser(@RequestParam(value="id",required=false) Integer id, 
			Map<String, Object> map){
		System.out.println("modelAttribute method");
		if(id != null){
			//模拟从数据库中获取对象
			User user = new User(1, "Tom", "123456", "[email protected]", 12);
			System.out.println("从数据库中获取一个对象: " + user);
			
			map.put("user", user);
		}
	}
	
	/**
	 * 运行流程:
	 * 1. 执行 @ModelAttribute 注解修饰的方法: 从数据库中取出对象, 把对象放入到了 Map 中. 键为: user
	 * 2. SpringMVC 从 Map 中取出 User 对象, 并把表单的请求参数赋给该 User 对象的对应属性.
	 * 3. SpringMVC 把上述对象传入目标方法的参数. 
	 * 
	 * 注意: 在 @ModelAttribute 修饰的方法中, 放入到 Map 时的键需要和目标方法入参类型的第一个字母小写的字符串一致!
	 * 
	 * SpringMVC 确定目标方法 POJO 类型入参的过程
	 * 1. 确定一个 key:
	 * 1). 若目标方法的 POJO 类型的参数木有使用 @ModelAttribute 作为修饰, 则 key 为 POJO 类名第一个字母的小写
	 * 2). 若使用了  @ModelAttribute 来修饰, 则 key 为 @ModelAttribute 注解的 value 属性值. 
	 * 2. 在 implicitModel 中查找 key 对应的对象, 若存在, 则作为入参传入
	 * 1). 若在 @ModelAttribute 标记的方法中在 Map 中保存过, 且 key 和 1 确定的 key 一致, 则会获取到. 
	 * 3. 若 implicitModel 中不存在 key 对应的对象, 则检查当前的 Handler 是否使用 @SessionAttributes 注解修饰, 
	 * 若使用了该注解, 且 @SessionAttributes 注解的 value 属性值中包含了 key, 则会从 HttpSession 中来获取 key 所
	 * 对应的 value 值, 若存在则直接传入到目标方法的入参中. 若不存在则将抛出异常. 
	 * 4. 若 Handler 没有标识 @SessionAttributes 注解或 @SessionAttributes 注解的 value 值中不包含 key, 则
	 * 会通过反射来创建 POJO 类型的参数, 传入为目标方法的参数
	 * 5. SpringMVC 会把 key 和 POJO 类型的对象保存到 implicitModel 中, 进而会保存到 request 中. 
	 * 
	 * 源代码分析的流程
	 * 1. 调用 @ModelAttribute 注解修饰的方法. 实际上把 @ModelAttribute 方法中 Map 中的数据放在了 implicitModel 中.
	 * 2. 解析请求处理器的目标参数, 实际上该目标参数来自于 WebDataBinder 对象的 target 属性
	 * 1). 创建 WebDataBinder 对象:
	 * ①. 确定 objectName 属性: 若传入的 attrName 属性值为 "", 则 objectName 为类名第一个字母小写. 
	 * *注意: attrName. 若目标方法的 POJO 属性使用了 @ModelAttribute 来修饰, 则 attrName 值即为 @ModelAttribute 
	 * 的 value 属性值 
	 * 
	 * ②. 确定 target 属性:
	 * 	> 在 implicitModel 中查找 attrName 对应的属性值. 若存在, ok
	 * 	> *若不存在: 则验证当前 Handler 是否使用了 @SessionAttributes 进行修饰, 若使用了, 则尝试从 Session 中
	 * 获取 attrName 所对应的属性值. 若 session 中没有对应的属性值, 则抛出了异常. 
	 * 	> 若 Handler 没有使用 @SessionAttributes 进行修饰, 或 @SessionAttributes 中没有使用 value 值指定的 key
	 * 和 attrName 相匹配, 则通过反射创建了 POJO 对象
	 * 
	 * 2). SpringMVC 把表单的请求参数赋给了 WebDataBinder 的 target 对应的属性. 
	 * 3). *SpringMVC 会把 WebDataBinder 的 attrName 和 target 给到 implicitModel. 
	 * 近而传到 request 域对象中. 
	 * 4). 把 WebDataBinder 的 target 作为参数传递给目标方法的入参. 
	 */
	@RequestMapping("/testModelAttribute")
	public String testModelAttribute(User user){
		System.out.println("修改: " + user);
		return "success";
	}

转发显示jsp页:

request user: ${requestScope.user }

五、视图和视图解析器

请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个ModelAndView 对象,它包含了逻辑名和模型对象的视图。

Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是Excel、JFreeChart 等各种表现形式的视图。

对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦。

六、重定向和转发

  • 一般情况下,控制器方法返回字符串类型的值会被当成逻 辑视图名处理
  • 如果返回的字符串中带 forward:redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和redirect: 当成指示符,其后的字符串作为 URL 来处理

–redirect:success:请求重定向到  ->  站点入口所在目录/success ,继续交由handler处理

–forward:success:请求转发到    ->  站点入口所在目录/success ,继续交由handler处理【不过转发时,请求路径是不会跳转的】

测试页:

@RequestMapping("/testredirect")
public String testRedirect(){

System.out.println("test-redirect");

//return "redirect:/index";
return "forward:/success";

}

七、静态资源请求

核心说明:
1、如果url请求对象是 xxx.jsp ,就按照网站路径去查找对应的文件。
2、如果url请求对象不是 xxx.jsp 比如 xx.html 或者 xx ,就交给视图解析器【如果设置了前缀和后缀,就转换成最终路径】去查询路径中是否存在文件。

这样,就造成了无法直接请求静态资源的问题:(在配置开发环境中已提到)

为了能够在网页中请求静态资源,如加载js和css等,所以需要  编辑   转发配置器。

 <!--  
		default-servlet-handler 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,
		它会对进入 DispatcherServlet 的请求进行筛查, 如果发现是没有经过映射的请求, 就将该请求交由 WEB 应用服务器默认的 
		Servlet 处理. 如果不是静态资源的请求,才由 DispatcherServlet 继续处理

		一般 WEB 应用服务器默认的 Servlet 的名称都是 default.
		若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定
		
	-->
	<mvc:default-servlet-handler/>
	<!-- 前面的 mvc:default-servlet-handler 可以解决静态资源了,但是让其他经过handler的请求,又失效了,所以配置了下面的 mvc:annotation-driven 来解决问题 -->
	<mvc:annotation-driven></mvc:annotation-driven>

 

 

 

springmvc基础-请求映射总结

@RequestMapping  请求映射总结

注意:

@RequestMapping(“/helloworld”)
public String hello( HttpServletRequest request ,HttpServletResponse response){
System.out.println(“hello request” + request.toString());
System.out.println(“hello response” + response.toString());
return “success”;
}
handler 控制器:函数参数 可以有request和 response,可以有其中一个,也可以都没有,request和response 都是spring容器注入的。他们是接口。还有将request 和 response 内部对象  作为形参的 。另外也可以将  map【返回值ModelAndView中的model】作为形参。

经过了测试:如果  控制器的映射是这个–>@RequestMapping("/") 那么访问网站根目录时,还是以 网站根目录下的 index.jsp、 index.html  等做为结果 返回给浏览器。


一、请求映射-路径区分

1、请求映射-路径区分-基础

<a href="springmvc/testRequestMapping">Test RequestMapping</a>
package com.test.springmvc.handlers;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

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

@Controller // spring里面 又名handler 处理器
public class HelloWorld {

	/**
	 * 1、使用RequestMapping 注解来映射 请求的url
	 * 2、返回值会通过视图解析器解析为实际的物理视图,
	 * 对于org.springframework.web.servlet.view.InternalResourceViewResolver
	 * 会做如下解析,prefix + returnVal + suffix 得到实际的物理视图。然后做转发操作。
	 * 即 WEB-INF/views/success.jsp
 	 */
	@RequestMapping("/helloworld")
	public String hello( HttpServletRequest request,HttpServletResponse response){
		System.out.println("hello request" + request.toString());
		System.out.println("hello response" + response.toString());
		return "success";
	}
	
}

2、请求映射-路径区分-利用post方式

<form action="springmvc/testMethod" method="POST">
	<input type="submit" value="submit"/>
</form>
/**
	 * 常用: 使用 method 属性来指定请求方式
	 */
	@RequestMapping(value = "/testMethod", method = RequestMethod.POST)
	public String testMethod() {
		System.out.println("testMethod");
		return "success";
	}

3、请求映射-路径区分-利用请求参数和请求头

	<a href="springmvc/testParamsAndHeaders?username=atguigu&age=10">Test ParamsAndHeaders</a>
/**
	 * 了解: 可以使用 params 和 headers 来更加精确的映射请求. params 和 headers 支持简单的表达式.
	 * 
	 * @return
	 */
	@RequestMapping(value = "testParamsAndHeaders", params = { "username","age!=10" }, headers = { "Accept-Language=en-US,zh;q=0.8" })
	public String testParamsAndHeaders() {
		System.out.println("testParamsAndHeaders");
		return "success";
	}

4、请求映射-路径区分-利用ant风格

Ant 风格资源地址支持3种匹配符:
?:匹配文件名中的一个字符
*:匹配一层路径
**:** 匹配多层路径

测试: <a href=”springmvc/testAntPath/mnxyz/abc”>Test AntPath</a>

@RequestMapping("/testAntPath/*/abc")
	public String testAntPath() {
		System.out.println("testAntPath");
		return "success";
	}

二、请求映射-信息传递

1、请求映射-信息传递-利用路径变量

测试: <a href=”springmvc/testPathVariable/1″>Test PathVariable</a>

/**
	 * @PathVariable 可以来映射 URL 中的占位符到目标方法的参数中.
	 * @param id
	 * @return
	 */
	@RequestMapping("/testPathVariable/{id}")
	public String testPathVariable(@PathVariable("id") Integer id) {
		System.out.println("testPathVariable: " + id);
		return "success";
	}

2、请求映射-信息传递-REST风格

示例:
/order/1 HTTP  GET :得到id = 1的 order –
/order/1 HTTP DELETE:删除 id = 1 的 order –
/order/1 HTTP PUT:更新 id = 1的 order –
/order HTTP POST:新增 order –

HiddenHttpMethodFilter:浏览器 form 表单只支持 GET与POST请求,而DELETE、PUT 等method并不支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使得支持 GET、POST、PUT 与DELETE 请求。

第一步:首先在web.xml的添加过滤器

<!-- 
	配置 org.springframework.web.filter.HiddenHttpMethodFilter: 可以把 POST 请求转为 DELETE 或 POST 请求 
	-->
	<filter>
		<filter-name>HiddenHttpMethodFilter</filter-name>
		<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>HiddenHttpMethodFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

第二步:编写测试网页

<form action="springmvc/testRest/1" method="post">
		<input type="hidden" name="_method" value="PUT"/>
		<input type="submit" value="TestRest PUT"/>
	</form>
	<br><br>
	
	<form action="springmvc/testRest/1" method="post">
		<input type="hidden" name="_method" value="DELETE"/>
		<input type="submit" value="TestRest DELETE"/>
	</form>
	<br><br>
	
	<form action="springmvc/testRest" method="post">
		<input type="submit" value="TestRest POST"/>
	</form>
	<br><br>
	
	<a href="springmvc/testRest/1">Test Rest Get</a>
	<br><br>

3、请求映射-信息传递-利用请求参数

	/**
	 * @RequestParam 来映射请求参数. value 值即请求参数的参数名 required 该参数是否必须. 默认为 true
	 *               defaultValue 请求参数的默认值
	 */
	@RequestMapping(value = "/testRequestParam")
	public String testRequestParam(
			@RequestParam(value = "username") String un,
			@RequestParam(value = "age", required = false, defaultValue = "0") int age) {
		System.out.println("testRequestParam, username: " + un + ", age: "
				+ age);
		return "success";
	}

测试: <a href=”springmvc/testRequestParam?username=atguigu&age=11″>Test RequestParam</a>

其实也可以用表单的post方法,来传递请求参数,因为控制器也能解析的。

第三步:编写控制器

/**
	 * Rest 风格的 URL. 以 CRUD 为例: 新增: /order POST 修改: /order/1 PUT update?id=1 获取:
	 * /order/1 GET get?id=1 删除: /order/1 DELETE delete?id=1
	 * 
	 * 如何发送 PUT 请求和 DELETE 请求呢 ? 1. 需要配置 HiddenHttpMethodFilter 2. 需要发送 POST 请求
	 * 3. 需要在发送 POST 请求时携带一个 name="_method" 的隐藏域, 值为 DELETE 或 PUT
	 * 
	 * 在 SpringMVC 的目标方法中如何得到 id 呢? 使用 @PathVariable 注解
	 * 
	 */
	@RequestMapping(value = "/testRest/{id}", method = RequestMethod.PUT)
	public String testRestPut(@PathVariable Integer id) {
		System.out.println("testRest Put: " + id);
		return "success";
	}

	@RequestMapping(value = "/testRest/{id}", method = RequestMethod.DELETE)
	public String testRestDelete(@PathVariable Integer id) {
		System.out.println("testRest Delete: " + id);
		return "success";
	}

	@RequestMapping(value = "/testRest", method = RequestMethod.POST)
	public String testRest() {
		System.out.println("testRest POST");
		return "success";
	}

	@RequestMapping(value = "/testRest/{id}", method = RequestMethod.GET)
	public String testRest(@PathVariable Integer id) {
		System.out.println("testRest GET: " + id);
		return "success";
	}

4、请求映射-信息传递-利用请求头

测试: <a href=”springmvc/testRequestHeader”>Test RequestHeader</a>

/**
	 * 了解: 映射请求头信息 用法同 @RequestParam
	 */
	@RequestMapping("/testRequestHeader")
	public String testRequestHeader(
			@RequestHeader(value = "Accept-Language") String al) {
		System.out.println("testRequestHeader, Accept-Language: " + al);
		return "success";
	}

5、请求映射-信息传递-利用cookie值

测试:<a href=”springmvc/testCookieValue”>Test CookieValue</a>

/**
	 * 了解:
	 * 
	 * @CookieValue: 映射一个 Cookie 值. 属性同 @RequestParam
	 */
	@RequestMapping("/testCookieValue")
	public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) {
		System.out.println("testCookieValue: sessionId: " + sessionId);
		return "success";
	}

6、请求映射-信息传递-form表单的pojo

将  表单信息  转换成  bean  ,支持级联属性。如:dept.deptId、dept.address.tel 等

1、测试页:

<form action="springmvc/testPojo" method="post">
		username: <input type="text" name="username"/>
		<br>
		password: <input type="password" name="password"/>
		<br>
		email: <input type="text" name="email"/>
		<br>
		age: <input type="text" name="age"/>
		<br>
		city: <input type="text" name="address.city"/>
		<br>
		province: <input type="text" name="address.province"/>
		<br>
		<input type="submit" value="Submit"/>
	</form>

2、控制页

	/**
	 * Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配, 自动为该对象填充属性值。支持级联属性。
	 * 如:dept.deptId、dept.address.tel 等
	 */
	@RequestMapping("/testPojo")
	public String testPojo(User user) {
		System.out.println("testPojo: " + user);
		return "success";
	}

3、Bean [估计是调用默认构造函数,然后set属性,完成bean创建]

bean – user

public class User {
	
	private Integer id;
	
	private String username;
	private String password;

	private String email;
	private int age;
	
	private Address address;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	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 String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	public User() {}
}

bean-address

public class Address {

	private String province;
	private String city;

	public String getProvince() {
		return province;
	}

	public void setProvince(String province) {
		this.province = province;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}
}

 

显示jsp页:

<%@ taglib uri=“http://java.sun.com/jsp/jstl/core” prefix=“c”%>

request user: ${requestScope.user }

核心摘要:在控制器中,自动生成的pojo的 User类型对象。会自动产生一个首字母小写的类型对象的关键字,并将关键字和其类型对象值,一同传入request中。

如这里:会将 “user” 作为关键字,user 对象作为value值,存放到request中。 

操作和 request.setAttribute("user", user);一样
如果控制器的pojo参数用了 @ModelAttribute 注解标记,那么标记值若是XXX,则效果就像 request.setAttribute("XXX", user);一样

//举例如下:
//控制器中 用 @ModelAttribute&nbsp;注解标记 的情况
public String testPojo(@ModelAttribute(value ="test") User user) {
	System.out.println("testPojo: " + user);
	return "success";
}
//在转发显示页 用 ${requestScope.test} 调用。当然别忘记添加 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

总之一旦有pojo对象生成,那显示jsp页就可以直接调用${requestScope.标记名 }


7、请求映射-信息传递-原始servletapi作为参数

测试:<a href=”springmvc/testServletAPI”>Test ServletAPI</a>

/**
	 * 可以使用 Serlvet 原生的 API 作为目标方法的参数 具体支持以下类型
	 * 
	 * HttpServletRequest 
	 * HttpServletResponse 
	 * HttpSession
	 * java.security.Principal 
	 * Locale InputStream 
	 * OutputStream 
	 * Reader 
	 * Writer
	 * @throws IOException 
	 */
	@RequestMapping("/testServletAPI")
	public void testServletAPI(HttpServletRequest request,
			HttpServletResponse response, Writer out) throws IOException {
		System.out.println("testServletAPI, " + request + ", " + response);
		out.write("hello springmvc");
//		return "success";
	}

Handler的函数参数可以添加上面的这些,其实本质上来说:函数参数只有 request和response。其他的参数都是这些方法里面包括的。比如writer就是response.getWriter()


springmvc踩坑-配置视图解析前后缀内容重复

配置文件里面的 配置内容重复了。

当时在springmvc中,配置转发器时,发现视图解析器 居然有两个。一个添加了前缀和后缀,一个没有添加。

然后我在handler【也叫controller】中,    —》{这个是非注解配置的handler}

@Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception{ 
    
    //新建ModelAndView
    ModelAndView modelAndView =  new ModelAndView();
    //相当 于request的setAttribut,在jsp页面中通过itemsList取数据
    modelAndView.addObject("itemsList", ""); 
   
 
    //指定视图 (本来这里就是 最终返回地址了,但是视图解析器有前缀和后缀 干扰了;正确做是删除视图解析器的前缀和后缀)
    modelAndView.setViewName("/WEB-INF/views/success.jsp");
    
    //或者 正确的做法 这里返回success;在视图解析器添加 前缀和后缀
    //modelAndView.setViewName("success");

    return modelAndView;

}

发现,返回的路径一直是:/WEB-INF/views/WEB-INF/views/success.jsp.jsp
所以一直报错了。。。