spring mvc基础
@ kingkiller | Friday, Jan 29, 2021 | 3 minutes read | Update at Friday, Jan 29, 2021

了解MVC设计模式的思想,学习spring mvc基础,ssm框架现在虽说没有springboot轻便,但是了解底层基础和演变过程会对boot的学习有很多益处

Spring MVC

前期的设计模式

1.模式一(Model One)

JSP:JSP的出现既解决了Servlet不适合向外输出网页的问题,也解决了HTML无法展示动态数据的问题!

​ 只有JSP开发项目

    1. 需要接收请求中的数据

        2. 需要对请求进行处理
                3. 需要处理业务逻辑
                            4. 需要访问数据库
                                    5. 将请求处理的结果展示给用户

要在JSP中完成上面的工作,这就意味着要在JSP中写大量的Java代码,容易造成JSP页面结构的混乱,不利于后期的扩展和维护.

2.模式二(Model Two)

Servlet+JavaBean+JSP:

Bean:在计算机英语中,表示可重用的组件

JavaBean:广义:使用Java语言编写的可重用的组件

​ 狭义:实体类,用于封装数据的Java类

​ 业务Bean,专门用于处理业务逻辑的Java类

Servlet:
  1. 获取请求中的数据

  2. 调用某一个JavaBean对请求进行处理

  3. 调用某一个JSP展示请求处理的结果

JavaBean:
  1. 处理请求

  2. 处理业务逻辑

  3. 访问数据

  4. 封装数据库

JSP:

1.将请求处理的结果展示给用户

MVC设计模式

MVC设计模式是一种通用的软件编程思想

在MVC设计模式中认为,任何软件都可以分为三部分组成:

1.控制程序流转的控制器(Controller)

2.封装数据处理的模型(Model)

3.负责展示数据的视图(View)

并且在MVC设计思想中要求一个符合MVC设计思想的软件应该保证上面三部分相互独立,互不干扰,每一个部分只负责自己擅长的部分.

如果某一个模块发生变化,应该尽量做到不影响其他两个模块.这样做的好处是,软件的结构会变的更加的清晰,可读性强.有利于后期的扩张和维护,并且代码可以实现复用.

JavaEE经典架构(SSM)

初识SpringMVC

1.Servlet的缺点

1.通常情况下,一个Servlet类只负责处理一个请求,若项目中有成百上千个处理,就要成百上千个Servlet类,这样会使Servlet类暴涨

2.在Servlet3.0版本之前,每一个Servlet都需要在web.xml进行配置

3.当通过客户端提交参数到服务器,通过Servlet进行接收,无论数据本身是什么格式,在Servlet中一律按照字符串进行接收,后期需要进行类型转换,复杂类型还需要特殊处理

4.Servlet具有容器依赖性,必须放在服务器中运行,不利于单元测试

2.SpringMVC简介

SpringMVC是一个spring框架的一个模块,spring和springmvc无需中间层

3.快速入门

1.创建Maven web工程SpringMVCdemo

2.导入相关依赖

<!-- 集中定义依赖版本号 -->
<properties>
	<junit.version>4.10</junit.version>
	<spring.version>4.1.3.RELEASE</spring.version>
</properties>
<dependencies>
	<!-- 单元测试 -->
	<dependency>
		<groupId>junit</groupId>
		<artifactId>junit</artifactId>
		<version>${junit.version}</version>
		<scope>test</scope>
	</dependency>

	<!-- SpringMVC -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>${spring.version}</version>
	</dependency>
	
	<!-- Servlet支持Request和Response -->
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>servlet-api</artifactId>
		<version>2.4</version>
		<scope>provided</scope>
	</dependency>
	
	<!-- java对象转换json的工具类 -->
	<dependency>
		<groupId>com.fasterxml.jackson.core</groupId>
		<artifactId>jackson-databind</artifactId>
		<version>2.5.1</version>
	</dependency>
</dependencies>

3.配置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" version="2.5">
  <display-name>SpringMVCdemo</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <!-- 配置前端控制器DispatcherServlet -->
  <servlet>
  	<servlet-name>springmvc</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<!-- 配置springmvc核心配置文件的位置,默认Springmvc的配置文件是在WEB-INF目录下,默认的名字为springmvc-servlet.xml,如果要放在其他目录,则需要指定如下配置:
		-->
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:springmvc-config.xml</param-value>
		</init-param>		
  </servlet>
  <!-- 配置前端控制器拦截除JSP以外的所有的请求 -->
  <servlet-mapping>
  	<servlet-name>springmvc</servlet-name>
  	<url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

4.创建WEB-INF/pages/home.jsp文件

5.在src/main/java中创建com.kingkiller.controller包,在包中创建HelloController

6.配置核心配置文件

<?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:mvc="http://www.springframework.org/schema/mvc"	xmlns:context="http://www.springframework.org/schema/context"	xsi:schemaLocation="http://www.springframework.org/schema/mvc						http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd						http://www.springframework.org/schema/beans			http://www.springframework.org/schema/beans/spring-beans-4.0.xsd						http://www.springframework.org/schema/context     		http://www.springframework.org/schema/context/spring-context-4.0.xsd">
	<!-- 1.配置前端控制器放行静态资源(html/css/js等,否则静态资源将无法访问) -->
	<mvc:default-servlet-handler/>
	<!-- 2.配置注解驱动,用于识别注解(比如@Controller) -->
	<mvc:annotation-driven></mvc:annotation-driven>
	<!-- 3.配置需要扫描的包:spring自动去扫描 base-package 下的类,
		如果扫描到的类上有 @Controller、@Service、@Component等注解,
		将会自动将类注册为bean 
	 -->
	<context:component-scan base-package="com.kingkiller.controller">
	</context:component-scan>
	<!-- 4.配置内部资源视图解析器
		prefix:配置路径前缀
		suffix:配置文件后缀
	 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
</beans>

6.编写HelloController类,完成需求,并运行测试

@Controller
//@RequestMapping("/HelloController")
public class HelloController {
    @RequestMapping("/hello")
    public String testHello() {
        System.out.println("hello springmvc");
        return "home";
    }
}

SpringMVC参数绑定

1.简单类型参数绑定

1.需求:

​ 浏览器请求:localhost:8080/SpringMVCdemo/testParam1?name=张飞&age=20&addr=中国

 	@RequestMapping("/testParam1")
    public String testParam1(String name,Integer age,String addr) {
        System.out.println("name="+name);
        return "home";//其实是一个转发的过程
    }

2.包装类型参数绑定:

​ 浏览器请求:localhost:8080/SpringMVCdemo/testParam2?name=刘备&age=18&addr=中国

在com.kingkiller.pojo包中创建User类

package com.kingkiller.pojo;
public class User {
    private String name;
    private int age;
    private String addr;
}

注意:这里需自己补全成员变量的get和set方法,以及无参构造和有参构造

编写测试类

	@RequestMapping("/testParam2")
    public String testParam2(User user) {
        System.out.println("name="+user.getName());
        System.out.println("age="+user.getAge());
        System.out.println("addr="+user.getAddr());
        return "home";
    }

3.日期类型参数绑定:

​ 浏览器请求:localhost:8080/SringMVCdemo/testParam3?date=2020/2/8 13:00:00

    @RequestMapping("/testParam3")
    public String testParam3(Date date) {
        System.out.println("data="+date);
        return "home";
    }

注意:如果在请求中用的是date=2020-2-8的形式,可能会出现400错误:请求参数类型不匹配.因为SpringMVC底层默认使用/来分割.我们可以通过更改底层代码实现的方式来解决:在Cotroller类中添加自定义日期转换格式的代码:

	/* 自定义日期转换格式 */
	@InitBinder
	public void InitBinder (ServletRequestDataBinder binder){
		binder.registerCustomEditor(java.util.Date.class, 
			new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true)
		);
	}

跳转和乱码处理

1.请求转发

其实return “home”;本身就是一个请求转发,将请求转发到home.jsp,因为请求转发是一次1请求一次响应,所以浏览器地址栏不会发生改变,显示的依然是@RequestMapping后配置的路径

我们还可以通过return “forward:**“的方式来将请求转发到其他的方法中

	@RequestMapping("/testForward")
    public String testForward() {
        System.out.println("testForward方法执行了");
        return "forward:/hello";
    }

在浏览器中输入localhost:8080/SpringMVCdemo/testForward最终会跳转到home.jsp,但浏览器地址依然是testForword,说明了请求转发只会请求一次

2.重定向

通过return “redirect:/**“的方式可以完成请求的重定向

	@RequestMapping("/testRedirect")
    public String testRedirect() {
        System.out.println("testRedirect方法执行了");
        return "redirect:/hello";
    }

在浏览器中输入localhost:8080/SpringMVCdemo/testRedirect,最终结构会跳转到home.jsp,但浏览器地址会改成/hello,因为请求重定向将地址定向到了/hello,testHello方法又发生了请求转发跳转到home.jsp

3.乱码问题:

​ Servlet:

  1. 如果是GET提交,并且tomcat为8.0以后的版本,tomcat底层已经处理了GET提交的中文乱码问题,所以GET提交在tomcat8.0以后的版本中没有乱码!

  2. 如果是POST提交,无论实哪个版本的tomcat服务器,获取中文参数时都会有乱码问题

    解决:request.setCharacterEncoding(“utf-8”)

    springmvc中提供了处理POST提交中文参数乱码方法:在web.xml文件中配置一个乱码处理过滤器.

    <filter>
       <filter-name>encodingFilter</filter-name>
       <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
       <init-param>
           <param-name>encoding</param-name>
           <param-value>UTF8</param-value>
       </init-param>
    </filter>
    <filter-mapping>
       <filter-name>encodingFilter</filter-name>
       <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    我们创建在webapps下创建form.html进行测试(注意:不能建在WEB-INF文件里,应建在webapps文件夹内WEB-INF文件夹外)

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    </head>
    <body>
       <h1>POST提交</h1>
       <form action="http://localhost:8080/SpringMVCdemo/testParam5" method="POST">
           用户名:<input type="text" name="user" value="username"/>
           爱好: <input type="checkbox" name="like" value="篮球"/>篮球
                <input type="checkbox" name="like" value="足球"/>足球
           <input type="submit" value="提交">
       </form>
    </body>
    </html>
    

    在Cotroller类中编写测试方法:

        @RequestMapping("/testParam5")
        public String testParam5(String user,String[] like) {
            System.out.println("user:"+user);
            System.out.println("like:"+Arrays.toString(like));
            return "home";
        }
    

    会发现控制台中正确的输出了中文

SpringMVC响应数据

1.Model的使用

​ 从Servlet带数据到JSP:(通过request域带数据)

​ request.setAttribute(“xx”,xxx);

​ request.getRequestDispatcher(“xxx”).forward(req,res)

​ 从Controller带数据到JSP:(通过Model带数据)

​ model.addAttribute(“xx”,xxx);

第一种:以对象的方式响应数据

	@RequestMapping("/testModel")
    public String testModel(Model model) {
        //声明一个User对象,将User对象存入Model中
        User u1 = new User("张三",20,"北京");
        model.addAttribute("user",u1);
        //转发到home.jsp
        return "home";
    }

第二种:以集合的方式响应数据

	@RequestMapping("/testModel2")
    public String testModel2(Model model) {
        //声明一个User对象集合
        User u1 = new User("king",18,"china");
        User u2 = new User("queen",20,"china");
        List<User> list = new ArrayList<>();
        list.add(u2);
        list.add(u1);
        model.addAttribute("ulist",list);
        return "home";
    }

在hmoe.jsp中通过EL的方式读取数据并输出

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>springmvc...home.jsp</h1>
	${ user.name }<br/>
	${ user.age } 
	<hr/>
	${ ulist[0].name }
	${ ulist[1].name }
</body>
</html>

2.返回JSON数据

JSON是JS对象格式转换过来的一种非常流行的数据传输/交换格式

JSON中包含的数据结构是key-value格式(键值对)

1.JSON是用花括号括起来的一组内容,其中的数据是key-value结构

2.JSON中的key只能是字符串(可以加上数组)

可以通过@ResponseBody注解的方法来将返回的数据转换成JSON的格式再响应

	@RequestMapping("/testJSON")
    @ResponseBody
    public User testJSON() {
        //声明一个User对象,将User对象以JSON格式返回
        User u1 = new User("张三",20,"北京");
        return u1;
    }