SpringMVC 笔记【上】

16 篇文章 0 订阅

文章主要内容:

  1. HelloWorld
  2. DispatherServlet配置
  3. RequestMapping注解
  4. 获取请求数据
  5. 处理模型数据
  6. @ModelAttribute
  7. 转发与重定向

SpringMVC

一、 SpringMVC核心技术

1 HelloWorld

1.1 导入依赖包

在这里插入图片描述

1.2 配置 web.xml 的 DispatcherServlet

在项目的web.xml中配置DispatcherServlet:

<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
    <servlet-name>springDispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:springmvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
    <servlet-name>springDispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

主要修改:

  1. <param-value>classpath:springmvc.xml</param-value>
  2. <url-pattern>/</url-pattern>
1.3 创建index.jsp、success.jsp及controller

index.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<a href="helloWorld">HELLO world</a>
</body>
</html>

success.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<h1>success</h1>
</body>
</html>

controller

package com.cyt.controller;

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

@Controller
public class FirstController {

	@RequestMapping("/helloWorld")
	public ModelAndView helloworld() {
		System.out.println("helloworld");
		ModelAndView mv = new ModelAndView("/WEB-INF/views/success.jsp");
		return mv;
	}
}
  1. 在jsp中<a href="helloWorld">HELLO world</a>对应controller中@RequestMapping("/helloWorld")

  2. 这里用到的 ModelAndView 这种方式只在helloworld做介绍,很少实际应用此方法

1.4 创建springmvc.xml并配置

其实就是创建一个 spring bean configuration file

<?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.3.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">


	<context:component-scan base-package="com.cyt.controller"></context:component-scan>

</beans>

选择bean, context, mvc,并添加组件扫描<context:component-scan base-package="com.cyt.controller"></context:component-scan>

运行index.jsp即会跳转到success.jsp

1.5 配置视图解析器

上面在controller中用ModelAndView的方法跳转页面,但更多是用解析器操作:

  1. 在springmvc.xml中配置bean:
   <bean id="" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
       <property name="prefix" value="/WEB-INF/views/"></property>
       <property name="suffix" value=".jsp"></property>
   </bean>
  1. 改动controller
@Controller
public class FirstController {
    @RequestMapping("/helloWorld")
    public String helloworld() {
    System.out.println("helloworld");
    return "success";
    }
}

2 DispatcherServlet配置

2.1 <url-pattern>设置
  1. /* 的意思是“所有的请求”
  2. / 的意思是“所有的末被其它servlets接收并处理的请求”

在DispatcherServlet中,如果用了 /* 那么就会处理所有的请求,这意味着也会比JSP servlet优先处理.jsp请求。所以这也是为什么在DispacherServlet中通常配置的是<url-pattern>/</url-pattern>。通常情况下,只有在 Filter 中才会使用 /* ,这样可以监听所有的request请求

2.2 servlet-handler 和 annotation-driven

若将 DispatcherServlet 请求映射配置为 /, 则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求(如加入的JQuery), SpringMVC 会将他们当成一个普通请求处理, 因找不到对应处理器将导致错误。

解决:

在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/>。配置后,原来的请求又会出现问题,需要配置<mvc:annotation-driven />

将上面例子做改动:

springmvc.xml 添加:

<mvc:default-servlet-handler/>
<mvc:annotation-driven></mvc:annotation-driven>

在WebContent目录下添加resources文件夹,文件夹下添加a.txt

aaa
bbb
ccc
ddd

这样可直接访问resources下的a.txt : http://localhost:8080/springmvc/resources/a.txt 无需其他映射

如果不添加<mvc:annotation-driven></mvc:annotation-driven>,则反而会使 helloWorld 的映射失效


3 RequestMapping注解

Spring通过@Controller注解找到相应的控制器类后,还需要知道控制器内部对每一个请求是如何处理的,这就需要使用@RequestMapping注解类型,它用于映射一个请求或一个方法。使用时,可以标注在一个方法或一个类上。

示例所用index,jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	<h1>RequestMapping test</h1>
	<form action="login" method="post">
		Username<input type="text" name="username"/><br><br>
		Password<input type="text" name="password"/><br><br>
		<input type="submit" value="Submit"/>
	</form>
	<br>
	<a href="helloWorld">hello world</a>
</body>
</html>
3.1 标注在方法上:
@RequestMapping(value = "/login",params = {"username=jinondo","password"},method = RequestMethod.GET)
public String login() {
    System.out.println("Do Login");
    return "success";
}
  1. value/path =====》 RequestMapping 中默认配置value的属性,或者是path,两者为别名关系,功能一致:

@RequestMapping(value = "/login")@RequestMapping(path= "/login")

  1. params =====》为跳转所携带的参数

params = {"username","password"} 表示必须有两个参数分别为username和password

params = {"username=jinondo","password"} 表示必须有两个参数分别为username和password,且username的值为jinondo

params = {"!username","password"} 前面加个感叹号!,表示不能出现username的参数

  1. method =====》为对应请求方法为GET或POST

例如上面jsp中的表单:

<form action="login" method="post">
    Username<input type="text" name="username"/><br><br>
    Password<input type="text" name="password"/><br><br>
    <input type="submit" value="Submit"/>
</form>

method应和RequestMapping中method属性对应上才能正常运行

  1. 使用@PostMapping等

请求方法共有:

–@GetMapping

–@PostMapping

–@PutMapping

–@DeleteMapping

使用@PostMapping(path = "/login",params = {"username","password"})和使用@RequestMapping(value = "/login",params = {"username","password"},method = RequestMethod.POST) 效果一致

3.2 标注在类上:
@RequestMapping("/test")
@Controller
public class FirstController {

	@RequestMapping("/helloWorld")
	public String helloworld() {
		System.out.println("helloworld");
		return "success";
	}
	......
}

第一行@RequestMapping("/test")表示映射的地址得添加一个/test,即/test/helloWorld:

<a href="test/helloWorld">hello world</a>


4 获取请求数据

4.1 @RequestParam获取请求参数

index.jsp中添加:

<h1>RequestMapping test</h1>
<form action="${pageContext.request.contextPath }/test/addPerson" method="post">
    IdCard:<input type="text" name="idCard"/><br><br>
    Name:<input type="text" name="name"/><br><br>
    Age:<input type="text" name="age"/><br><br>
    <input type="submit" value="Submit"/>
</form>
<br>

controller:

@PostMapping("/addPerson")
public String add(@RequestParam(value="card", required = false)String idCard,String name,
                  @RequestParam(value="age", required = false, defaultValue = "0")String age) {
    System.out.println(idCard);
    System.out.println(name);
    System.out.println(age);
    return "success";
}

这里的 @PostMapping("/addPerson") 和 action="${pageContext.request.contextPath }/test/addPerson" 对应因为上个例子中RequestMapping设置在类前的@RequestMapping("/test")

在这里插入图片描述

  1. value属性:如果不配置value属性,则controller函数参数中的idCard必须与表单中的name一致为idCard;如果配置@RequestParam中的value属性则可以指定页面中的name属性的别名。
  2. required:默认为true,true为请求数据必须有name符合的指定参数,否则会报错,false则不会报错,设置为null
  3. defaultValue:设置没有同名参数时的默认值。
4.2 @CookieValue获取cookie

可以使用@CookieValue获取sessionId:

@PostMapping("/addPerson")
public String add(@RequestParam(value="idCard", required = false)String idCard,String name,
                  @RequestParam(value="age", required = false, defaultValue = "0")String age, @CookieValue("JSESSIONID")String sessionId) {
    System.out.println(idCard);
    System.out.println(name);
    System.out.println(age);
    System.out.println("cookie:JSESSION:" + sessionId);
    return "success";
}

@CookieValue("JSESSIONID")String sessionId获取session id

4.3 使用POJO获取参数
  1. 创建bean
public class Person {
	private String idCard;
	private String name;
	private Integer age;
	private Address address;
public class Address {
	private String city;
	private String province;
  1. controller
@PostMapping("/pojo")
public String pojo(Person person) {
    System.out.println(person);
    return "success";
}
  1. index.jsp
<h1>POJO test</h1>
<form action="${pageContext.request.contextPath }/test/pojo" method="post">
    IdCard:<input type="text" name="idCard"/><br><br>
    Name:<input type="text" name="name"/><br><br>
    Age:<input type="text" name="age"/><br><br>
    City:<input type="text" name="address.city"/><br><br>
    Province:<input type="text" name="address.province"/><br><br>
    <input type="submit" value="Submit"/>
</form>
<br>
  1. 必须保持参数和类的属性名一致
  2. 如果类中有关联关系,则用级联方法传递数据,例如 name=“address.city” 和 name=“address.province”
4.4 使用 Servlet API 作为入参

controller

@PostMapping("/pojo")
public String pojo(Person person,HttpServletRequest request,HttpServletResponse response, HttpSession session) throws IOException {
    System.out.println(person);
    System.out.println(request.getContextPath());
    System.out.println(response.getWriter().getClass().getName());
    System.out.println(session);
    return "success";
}

即使用原生的servlet的api

4.5 @PathVariable

此注解用于数据在url中,需要在controller中获取时。

例如

index.jsp:

<a href="${pageContext.request.contextPath }/test/order/20">Get Order</a>

controller:

@GetMapping("/order/{id}")
public String getOrder(@PathVariable("id")Integer orderId) {
    System.out.println("ID : " + orderId);
    return "success";
}

url为:http://localhost:8080/springmvc/test/order/20

需要获取到 20 则用此方法


5 处理模型数据

5.1 Model

提交页面index.jsp

<h1>Model test</h1>
<form action="${pageContext.request.contextPath }/test/model" method="post">
    IdCard:<input type="text" name="idCard"/><br><br>
    Name:<input type="text" name="name"/><br><br>
    Age:<input type="text" name="age"/><br><br>
    City:<input type="text" name="address.city"/><br><br>
    Province:<input type="text" name="address.province"/><br><br>
    <input type="submit" value="Submit"/>
</form>
<br>
  1. 使用 Model.addAttribute(Object arg0)

使用参数只有一个的重载函数,表示把数据装入request域中,在页面取出数据时只能使用类名的小写取出:

@PostMapping("/model")
public String model(Person person,Model model) {
    System.out.println(person);
    System.out.println("Do Logic");
    Date current = new Date();
    model.addAttribute(current);
    return "success";
}

success.jsp:

<body>
	<h1>success</h1>
	<hr>
	<h2>model result</h2>
	Current:${requestScope.date }
</body>

注意 ${requestScope.date },如果有多个同类型的则必须指定名字

  1. Model.addAttribute(String agrg0, @Nullable Object arg1)

使用有两个参数的addAttribute则表示指定名称装入request域。

@PostMapping("/model")
public String model(Person person,Model model) {
    System.out.println(person);
    System.out.println("Do Logic");
    Date current = new Date();
    model.addAttribute("current",current);
    return "success";
}

success.jsp中改为:

Current:${requestScope.current }

<body>
	<h1>success</h1>
	<hr>
	<h2>model result</h2>
	Current:${requestScope.current } <br> <br>
	Person: ${requestScope.person } <br> <br>
</body>

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

在model(即controller)函数形参中的数据会默认传到request域中,故刚刚我们没有在model中传入person类的数据,但依然能够在success.jsp中的requestScope中获取到,名称为类名小写,数据为我们提交页面(index.jsp)的表单中的数据。

可以重新设置一样的名称把表单提交的数据(即形参中的数据)覆盖掉,例如

Person per = new Person("aa123", "Tom", 20, null);
model.addAttribute("person",per);
5.2 Map

Map 和 Model 的使用并基本一致,无太大区别:

index.jsp:

<h1>Map Test</h1>
<a href="${pageContext.request.contextPath }/test/map">map test</a>
<br>

Controller:

@GetMapping("/map")
public String map(Map<String, Object> map) {
    Date date = new Date();
    map.put("time", date);
    return "success";
}

success.jsp:

<h2>map test</h2>
Time:${requestScope.time }<br> <br>
5.3 ModelAndView

第一节使用过的那个ModelAndView,实际开发较少使用。

index.jsp

<h1>ModelAndView Test</h1>
<a href="${pageContext.request.contextPath }/test/testModelAndView">ModelAndView test</a>
<br>

controller:

@GetMapping("/testModelAndView")
public ModelAndView modelAndView() {
    ModelAndView mv = new ModelAndView("success");
    mv.addObject("message", "the end of the fxxking world");
    return mv;
}

success,jsp

<h2>ModelAndView result</h2>
Message: ${requestScope.message }<br><br>
5.4 @SessionAttributes

如果需要往session域里放数据,可以用@SessionAttributes这个注解,但存在着问题!!!

例如:

在controller类前加上此注解:

@SessionAttributes("current")
@RequestMapping("/test")
@Controller
public class FirstController {
    ......

即在前面Model例子中有一个current的数据在调用model函数时会被加入session中,故在跳转其他页面,发送其他请求时,也可以取到这个数据(由于session的作用域)

index.jsp:

<h1>Map Test</h1>
<a href="${pageContext.request.contextPath }/test/map">map test</a>
<br>

<h1>Model test</h1>
<form action="${pageContext.request.contextPath }/test/model" method="post">
    IdCard:<input type="text" name="idCard"/><br><br>
    Name:<input type="text" name="name"/><br><br>
    Age:<input type="text" name="age"/><br><br>
    City:<input type="text" name="address.city"/><br><br>
    Province:<input type="text" name="address.province"/><br><br>
    <input type="submit" value="Submit"/>
</form>
<br>

success.jsp:

<h2>map result</h2>
Time:${requestScope.time }<br> <br>
Current from session :${sessionScope.current } <br> <br>

<h2>model result</h2>
Current from request :${requestScope.current } <br> <br>
Current from session :${sessionScope.current } <br> <br>

执行完会发现就算发送另一个请求,current这个数据依然可以从request域中取到,其实这个@SessionAttributes注解是把数据放入整个模型中,也放入session中了,故如果真要把数据放入session,可以使用原生的httpsession的api。


6 @ModelAttribute

此例子需要新创建一系列文件如下:

Student.java

public class Student {
	private String id;
	private String name;
	private Integer age;
	private Integer score;

student.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
	
	<h1>Insert</h1>
	<form action="${pageContext.request.contextPath }/student/update" method="post">
		<input type="hidden" name="id" value="1"/>
		Name:<input type="text" name="name" value="Jinondo"/><br><br>
		Age:<input type="text" name="age" value="21"/><br><br>
		
		<input type="submit" value="Submit"/>
	</form>

	<h1>Insert</h1>
	<form action="${pageContext.request.contextPath }/student/insert" method="post">
		
		Name:<input type="text" name="name"/><br><br>
		Age:<input type="text" name="age"/><br><br>
		Score:<input type="text" name="score"/><br><br>
		
		<input type="submit" value="Submit"/>
	</form>
</body>
</html>

studentSuccess.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>student Success</title>
</head>
<body>
	<h1>student Success Page</h1>
</body>
</html>
6.1 在方法定义上使用

在方法定义上使用 @ModelAttribute 注解:

Spring MVC 在调用目标处理方法前,会先逐个调用在方法级上标注了**@ModelAttribute** 的方法。

设计controller:

studentController.java

@RequestMapping("/student")
@Controller
public class StudentController {
	private static final String SUCCESS = "studentSuccess";
	
	@ModelAttribute
	public void prepareModel(Integer id,HttpServletRequest request,Model model) {
		System.out.println("prepare model data ......");
		String servletPath = request.getServletPath();
         // 判断是否是要执行update操作,即下一步的操作
		if (servletPath.equals("/student/update")) {
			System.out.println("Read student info from database by id" + id);
			// 模拟从数据库中取出id为1的原来的数据
			Student student = new Student("1", "jinondo", 21, 100);
			model.addAttribute("student", student);
		}
	}
	
	@PostMapping("/insert")
	public String insert(Student student) {
		System.out.println("insert student info ...... " + student);
		return SUCCESS; 	
	}
	
	@PostMapping("/update")
	public String update(Student student) {
		System.out.println("update student info : " + student);
		return SUCCESS; 	
	}
	
}

update更改数据后控制台输出:

prepare model data ......
Read student info from database by id1
update student info : Student [id=1, name=cyt, age=123, score=100]

使用此注解意义就在于 更新数据时有一些数据项是不允许更改的,但当要把表单提交的新的对象数据输入到数据库时,那个不允许更新的数据项则会是null等,则保存到数据库的是错误的数据。

使用@ModelAttribute则可以提前准备数据,让框架内部自动为我们绑定数据,例如上面的例子中,首先prepareModel的方法把原始的数据对象给了model,在update是则会取出student这个对象进行数据绑定,更改的数据在对象中进行更改,score没有更改,也在初始时已绑定到对象中,故不会造成数据出错。

6.2 在方法入参前使用

在方法的入参前使用 @ModelAttribute 注解:

  • 可以从隐含对象中获取隐含的模型数据,再与请求参数 绑定

  • 将方法入参对象添加到模型中

其实功能就是在方法入参时更改你的数据的“键”,如果那个键在模型中有,就直接进行参数绑定,没有就新建一个放入模型进行数据绑定

例如:

studentController.java

@PostMapping("/update")
public String update(@ModelAttribute("student")Student student) {
    System.out.println("update student info : " + student);
    return SUCCESS; 	
}

在形参前注解,表示把student数据键设置为student,正如上面我们在prepareModel中在模型中传入了一个键为student的数据,两者一致则直接拿来做数据绑定,如果我们设置为@ModelAttribute("stu"),则会新建一个键为stu的数据传入模型,这时模型就有了两个Student对象,上一节的效果则不复存在,即update时score会为null(指键为stu的那个对象)。


7 转发与重定向

7.1 redirect 重定向

用前面例子的代码演示:

@PostMapping("/insert")
public String insert(Student student) {
    System.out.println("insert student info ...... " + student);
    String redirectURL = "redirect:/test/testModelAndView";
    return redirectURL; 	
}

将controller方法的返回字符串前加上redirect: + 要重定向的url路径

这里的路径可以是请求:

String redirectURL = "redirect:/test/testModelAndView";

也可以是静态资源:

String redirectURL = "redirect:/index.jsp";

也可以是url:

String redirectURL = "redirect:http://www.instagram.com";

7.2 forward 请求转发
@PostMapping("/insert")
public String insert(Student student) {
    System.out.println("insert student info ...... " + student);
    String redirectURL = "forward:/index.jsp";
    return redirectURL;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值