Day44-SpringMVC

总结

我是最棒的!基础不牢,地动山摇!

SpringMVC

它是一款MVC型的框架,主要解决控制层这一领域的问题,是Spring的一个子项目

SpringMVC的大体流程

客户端发送的所有请求都会被SpringMVC核心控制器进行拦截,核心控制器会得到客户端请求的uri,通过与映射的配置文件(SpringMVC的核心配置文件)中进行匹配,匹配成功则执行控制器对外暴露的资源,匹配不成功返回404

SpringMVC创建控制器的三种方式

首先是核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
		xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" 
		id="WebApp_ID" version="3.1">
		
		<!-- springMvc的核心配置文件 -->
		<servlet>
			<!-- springMvc的核心控制器 -->
			<servlet-name>springMvc</servlet-name>
			<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
			<!-- 指明加载指定的springMvc的核心配置文件 -->
			<init-param>
				<param-name>contextConfigLocation</param-name>
				<param-value>classpath:applicationContext-mvc.xml</param-value>
			</init-param>
			<!-- 在服务器启动的时候就将核心控制器加载 -->
			<load-on-startup>1</load-on-startup>
		</servlet>
		
		<servlet-mapping>
			<!-- *.do 以do后缀结尾的请求都会进行拦截  不推荐使用 -->
			<!-- 
				<servlet-name>springMvc</servlet-name>
				<url-pattern>*.do</url-pattern> 
			-->
			
			<!-- /* 所有的请求都会进行拦截 jsp也会被拦截 不推荐使用 -->
			
			<!-- 
				<servlet-name>springMvc</servlet-name>
				<url-pattern>/*</url-pattern> 
			-->
			
			
			
			<!-- 所有的请求都会拦截,但是不会拦截jsp,推荐使用,但是设置了url-pattern为/之后,会覆盖掉tomcat里面的/,这样导致访问不了静态资源 -->
				<servlet-name>springMvc</servlet-name>
				<url-pattern>/</url-pattern> 
			
		</servlet-mapping>
</web-app>
  • 实现Controller接口(不推荐使用,每个Controller都需要在配置文件中写)
package cn.itsource.hello;

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

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

public class HelloController implements Controller{

	/**
	 * req 请求对象 底层自动注入值
	 * resp 响应对象 底层自动注入值
	 * ModelAndView 模型和视图
	 * Model 保存数据
	 * View 控制页面跳转
	 */
	@Override
	public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
		System.out.println(req);
		System.out.println(resp);
		
		ModelAndView mv = new ModelAndView();
		//设置要保存的数据
		mv.addObject("msg", "wdnmd");
		//控制页面跳转
		mv.setViewName("/hello.jsp");
		return mv;
	}
}
  • 实现HttpRequestHandler接口(不推荐,跟原生Servlet一样的方式)
package cn.itsource.hello;

import java.io.IOException;

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

import org.springframework.web.HttpRequestHandler;

public class HelloController1 implements HttpRequestHandler{

	@Override
	public void handleRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		System.out.println(req);
		System.out.println(resp);
		
		req.setAttribute("msg", "wdnmd");
		req.getRequestDispatcher("/hello.jsp").forward(req, resp);
	}
}
  • 注解实现(使用最多,推荐)
package cn.itsource.hello;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
//@Controller 这个注解表示将控制器交给spring管理
@Controller
public class HelloController2{
	
	//@RequestMapping 这个注解表示映射的路径
	@RequestMapping("/hello2")
	public ModelAndView hello2(){
		ModelAndView mv = new ModelAndView();
		mv.addObject("msg","sb");
		mv.setViewName("/hello.jsp");
		
		return mv;
	}
}

注解@Controller实现需要在核心配置文件中进行配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:context="http://www.springframework.org/schema/context"
		xmlns:mvc="http://www.springframework.org/schema/mvc"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		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.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc.xsd">
	<!-- 
		组件扫描器
		主要扫描: 
			@Controller这个注解
		
		扫描cn.itsource下面的包以及子子孙孙包下面所有的类,上面是否有@Controller这个注解,如果有这个注解
		就证明该类交给了spring管理
	
	 -->
	<context:component-scan base-package="cn.itsource"/>
    
    <!-- 静态资源放行   当你使用了该配置之后,@RequestMapping这个注解就失效了 -->
 	<mvc:default-servlet-handler/> 
 	
 	<!-- 开启springMvc特有注解的支持 -->
 	<mvc:annotation-driven/>

ResetFul风格

多用于查询和删除

传统风格:传递参数的时候

http://localhost:8080/user?id=1&name=xxx

ResetFul风格(逐渐流行)

http://localhost:8080/user/1/xxx

接收参数

SpringMVC 400错误 代表类型转换异常

扫描二维码关注公众号,回复: 11576931 查看本文章

接收参数的各种方式

package cn.itsource.param;

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

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

@Controller
@RequestMapping("/param")
public class ParamController {
	
	/**
	 * 方式1 普通属性接收参数
	 * @param name
	 */
	@RequestMapping("/01")
	public void save(String name){
		System.out.println(name);
	}
	
	/**
	 * 方式2 对象接收参数
	 */
	@RequestMapping("/02")
	public void param2(User user){
		System.out.println(user);
	}
	
	/**
	 * 方式3 传统方式接收参数
	 */
	@RequestMapping("/03")
	public void param3(HttpServletRequest req,HttpServletResponse resp,HttpSession session){
		System.out.println(req);
		System.out.println(resp);
		System.out.println(session);
		
		String name = req.getParameter("name");
		System.out.println(name);
	}
	
	/**
	 * 方式4 resetful风格
	 */
	@RequestMapping("/04/{id}/{name}")
	public void param4(@PathVariable("id")Long id,@PathVariable("name")String name){
		System.out.println(name + " " + id);
	}
	
	/**
	 * 方式5 基本不用
	 */
	@RequestMapping("/05")
	public void param5(@RequestParam("xxx")String name){
		System.out.println(name);
	}	
}

处理POST提交中文乱码

SpringMVC已经为我们提供了一个过滤器来解决,首先要在web.xml中进行配置。配置完毕后不会出现中文乱码问题

<!-- 解决POST提交方式中文乱码问题的过滤器 -->
		<filter>
			<filter-name>characterEncodingFilter</filter-name>
			<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
			<init-param>
				<param-name>encoding</param-name>
				<param-value>UTF-8</param-value>
			</init-param>
			<init-param>
				<param-name>forceEncoding</param-name>
				<param-value>true</param-value>
			</init-param>
		</filter>
		
		<filter-mapping>
			<filter-name>characterEncodingFilter</filter-name>
			<url-pattern>/*</url-pattern>
		</filter-mapping>

传输数据

传输数据的三种方式

package cn.itsource.tran;

import javax.servlet.http.HttpServletRequest;

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

@Controller
@RequestMapping("/tran")
public class TranController {
	/**
	 * 传递参数 方式1 Model
	 * @return
	 */
	@RequestMapping("/01")
	public String tran01(Model model){
		model.addAttribute("msg", "wdnmd");
		model.addAttribute("user",new User(1L,"cdd"));
		return "/hello.jsp";
	}
	
	/**
	 * 传递参数 方式2 ModelAndView
	 */
	@RequestMapping("/02")
	public ModelAndView tran02(){
		ModelAndView mv = new ModelAndView();
		mv.addObject("msg", "wdnmd");
		mv.addObject("user",new User(1L,"cdd"));
		mv.setViewName("/hello.jsp");
		return mv;
	}
	
	/**
	 * 传递参数 方式3 传统方式
	 */
	@RequestMapping("/03")
	public String tran03(HttpServletRequest req){
		req.setAttribute("msg", "wdnmd");
		req.setAttribute("user", new User(2L, "dnmd"));
		
		return "/hello.jsp";
	}
}

页面跳转

跳转的两种方式:请求转发和重定向 简写的时候都是请求转发

package cn.itsource.jump;

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

@Controller
@RequestMapping("/jump")
public class JumpController {
	
	/**
	 * 请求转发 方式1
	 * 简写 "/hello.jsp"
	 * 全写"forward:/hello.jsp"
	 * @return
	 */
	@RequestMapping("/01")
	public String forward1(){
		return "/hello.jsp";
	}
	
	/**
	 * 请求转发 方式2
	 * 简写 "/hello.jsp"
	 * 全写"forward:/hello.jsp"
	 * @return ModelAndView
	 */
	@RequestMapping("/02")
	public ModelAndView forward2(){
		ModelAndView mv = new ModelAndView();
		mv.setViewName("/hello.jsp");
		return mv;
	}
	
	/**
	 * 重定向 方式1
	 * 只能全写"redirect:/hello.jsp"
	 * @return
	 */
	@RequestMapping("/03")
	public String redirect1(){
		return "redirect:/hello.jsp";
	}
	
	/**
	 * 重定向 方式2
	 * 只能全写"redirect:/hello.jsp"
	 * @return
	 */
	@RequestMapping("/04")
	public ModelAndView redirect2(){
		ModelAndView mv = new ModelAndView();
		mv.setViewName("redirect:/hello.jsp");
		return mv;
	}
}

视图解析器

将重复的部分抽取成前缀和后缀

例如/hello.jsp 前缀为/,后缀为.jsp 配置了视图解析器之后就可以简写为hello。但是如果有特殊需求,例如/hello.html,这个时候就需要全写为forward:/hello.html

SpringMVC核心配置文件中

<!-- 设置视图解析器 -->
 	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
 		<!-- 设置视图解析器的前缀和后缀 -->
 		<property name="prefix" value="/"/>
 		<property name="suffix" value=".jsp"/>
 	</bean>
package cn.itsource.viewresovler;

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

@Controller
@RequestMapping("/view")
public class ViewResolverController {
	
	/**
	 * 这里访问的是/hello.jsp
	 * @return
	 */
	@RequestMapping("/02")
	public String forward2(){
		return "hello";
	}
	
	/**
	 * 想要访问html文件,无法简写
	 * 视图解析器设置的前缀和后缀都无法满足需求的时候,我们就需要全写来实现
	 * @return
	 */
	@RequestMapping("/01")
	public String forward1(){
		return "forward:/hello.html";
	}
}

上传和下载

上传

上传也需要在SpringMVC核心配置文件中配置一个文件解析器

<!-- 设置文件解析器 -->
 	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置文件最大上传的字节数 -->
 		<property name="maxUploadSize" value="5242880"/>
 	</bean>

上传的核心代码就是IOUtils.copy(is,os);

package cn.itsource.upload;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;

@Controller
public class UploadController {
	
	@RequestMapping(value = "/upload",method = RequestMethod.POST)
	public String upload(String username,MultipartFile headImage,HttpServletRequest req) throws IOException{
		//获取根路径
		String rootPath = req.getServletContext().getRealPath("/");
		//随机文件名
		String fileName = System.currentTimeMillis() + "." + FilenameUtils.getExtension(headImage.getOriginalFilename());
		//子路径
		String storePath = "/upload/" + fileName;
		//创建file对象
		File file = new File(rootPath, storePath);
		//判断文件夹是否存在,不存在就创建
		if(!file.getParentFile().exists()){
			file.getParentFile().mkdirs();
		}
		
		FileOutputStream fos = new FileOutputStream(file);
		InputStream is = headImage.getInputStream();
		//上传的核心代码
		IOUtils.copy(is, fos);
		return "upload";
	}
}

下载

道理与之前学过的下载相似,核心代码与上传相同

package cn.itsource.download;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

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

import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class DownloadController {
	
	@RequestMapping("/download")
	public String download(HttpServletRequest req,HttpServletResponse resp) throws IOException{
		//设置文件的mime类型
		resp.setContentType("application/x-msdownload");
		//设置下载的文件名
		resp.setHeader("Content-Disposition", "attachment; filename=1570621416809.jpg");
		//获取下载的路径,从upload获取
		String downloadPath = req.getServletContext().getRealPath("/upload");
		//创建file对象
		File file = new File(downloadPath, "1570621416809.jpg");
		
		FileInputStream fis = new FileInputStream(file);
		//获取输出流
		ServletOutputStream os = resp.getOutputStream();
		IOUtils.copy(fis, os);
		return "upload";
	}
}

SpringMVC的具体执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WVJGxGOx-1570626558022)(E:\ITSource\homework\JavaEE\1009Day44\resources\1.PNG)]

客户端发送请求,SpringMVC将所有的请求进行拦截,根据你的请求找到相应的处理对象(判断是走的配置还是注解请求),通过处理对象在找到相应的适配器对象,在执行目标方法之前,进行数据转换,格式化,验证等操作返回一个ModelAndView对象给SpringMVC核心控制器,然后找到对应的视图解析器,拼接我们的视图,拼接完毕后携带Model存储的数据,渲染到view界面(JSP等)中,最后展示给客户端

SpringMVC的具体执行流程

在这里插入图片描述

客户端发送请求,SpringMVC将所有的请求进行拦截,根据你的请求找到相应的处理对象(判断是走的配置还是注解请求),通过处理对象在找到相应的适配器对象,在执行目标方法之前,进行数据转换,格式化,验证等操作,然后再执行目标方法,返回一个ModelAndView对象给SpringMVC核心控制器,然后找到对应的视图解析器,拼接我们的视图,拼接完毕后携带Model存储的数据,渲染到view界面(JSP等)中,最后展示给客户端

猜你喜欢

转载自blog.csdn.net/t384061961/article/details/102470039