Spring-MVC

核心组件

  1. DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。
    DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
    1. 文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
    2. 通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个
      HandlerInterceptor拦截器);
    3. 通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
    4. 通过ViewResolver解析逻辑视图名到具体视图实现;
    5. 本地化解析;
    6. 渲染具体的视图等;
    7. 如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。
  2. HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
  3. HandlerAdapter:通过扩展处理器适配器,支持更多类型的处理器,调用处理器传递参数等工作。
  4. ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。

MVC执行过程

在这里插入图片描述
在这里插入图片描述

  1. 前端页面发送一个请求给DispatcherServlet,DispatcherServlet负责调度
  2. 将这个请求发送给HandleMapping,HandlerMapping会根据这个请求地址找到对应的处理器
  3. 将对应的处理器封装成处理器执行链返还给DispatcherServlet
  4. DispatcherServlet根据这个处理器执行链找到其处理器适配器
  5. 处理器适配器去执行这个处理器
  6. 处理器调用Service方法,根据其业务逻辑调用dao层对数据库进行操作,将结果一步一步向上返还给处理器。
  7. 处理器将结果封装成ModelAndView交给DispatcherServlet
  8. DispatcherServlet将ModelAndView对象交给视图解析器ViewResolver
  9. 视图解析器将封装了视图的view对象返还给DispatcherServlet
  10. 后者再找到view对象,并进行渲染。
  11. 形成一个响应对象,再将此对象交付给DispatcherServlet由其响应给前端。

/和/*的区别

  1. /不会匹配./jsp.不会导致重定向后再次访问spring 的DispatcherServlet
  2. /*会匹配./jsp.会出现返回jsp视图时再次进入spring的DispatcherServlet 类,
    导致找不到对应的controller所以报404错。

创建控制器类

@Controller 类注解
@RequestMapping (“请求地址”) 请求注解
RequestMapping 属性
@RequestMapping ("method=RequestMethod.GET,value=“请求名”)限定get请求
如果不填则默认为GET 和POST请求皆可

后端接收前端数据

  1. 通过HttpServletRequest方式
  • 接收的数据类型全是String类型

    @Controller
    public class Controller{
    	@RequestMapping("/test")
    	public String test(HttpRequest request){
    		String username = request.getParameter("username");
    		String age = request.getParameter("age");
    		return "success";
    	}
    }
    
  1. 在Spring框架中提供的接收参数的方法
    页面传值时的key=处理请求的方法的参数名
    @Controller
    public class Controller{
    	@RequestMapping("/test")
    	public String test(String username ,int age){
    		System.out.println("username= "+username,"age="+age);
    		return "success";
    	}
    }
    
  2. 使用控件名和对象的属性名一致的方式进行接收
    @Controller
    public class Controller{
    	@RequestMapping("/test")
    	public String test(Users user){
    		System.out.println("username= "+user.getUsername(),"age="+user.getAge());
    		return "success";
    	}
    }
    
  3. key值不一致的方式进行接收
    @Controller
    public class Controller{
    	@RequestMapping("/test")
    	public String test(@RequestParam(name="username")String name,@RequestParam(name="age",defaultValue="18")int age){//指定在页面中名为username的参数传入时对应name
    		System.out.println("username= "+user.getUsername(),"age="+user.getAge());
    		return "success";
    	}
    }
    

日期类型处理

后端接受前端日期类型
默认接收的是String类型以斜杠为分隔,例如 “2020/5/30”

  1. 日期处理工具包

    <dependency>
    	<groupId>joda-time</groupId>
    	<artifactId>joda-time</artifactId>
    	<version>2.9.9</version>
    </dependency>
    
spring配置文件:增加mvc命名空间以及
<mvc:annotation-driven/>
public String test(@DateTimeFormat(pattern = "yyyy-MM-dd")Date birthday){}

@DateTimeFormat可以标注在Bean的日期类型的属性上
后端返还日期类型给前端
@JsonFormat(parttern=“yyyy-MM-dd”)

后端向前端返还数据

Spring的return 是默认使用转发(request)的方式

  1. 通过HttpServletRequest方式
    @Controller
    public class Controller{
    	@RequestMapping("/test")
    	public String test(HttpRequest request){
    		String username = request.getParameter("username");
    		String age = request.getParameter("age");
    		request.setAttribute("username",username);
    		request.setAttribute("age",age);//request住阿奴发时显示,重定向时丢失
    		return "success";
    	}
    }
    
  2. ModelMap map ,默认作用域request
    @Controller
    public class Controller{
    	@RequestMapping("/test")
    	public String test(HttpServeletRequest request,ModelMap map){
    		String username = request.getParameter("username");
    		String age = request.getParameter("age");
    		request.setAttribute("username",username);
    		request.setAttribute("age",age);//request转发时显示,重定向时丢失
    		map.addAttribute("modelmapkey",username);
    		model.addAttribute(modelkey,username);
    
    		return "success";
    	}
    }
    
  3. ModelAndView 对象需要new,同时作为返回值类型
    @Controller
    public class Controller{
    	@RequestMapping("/test")
    	public ModelAndView test(HttpServeletRequest request){
    		String username = request.getParameter("username");
    		String age = request.getParameter("age");
    
    		ModelAndView modelAndView = new ModelAndView();
    		modelAndView.setViewName("success");
    		modelAndView.addObject("mvkey",username);
    		return modelAndView ;
    	}
    }
    

Session 存值
4. 使用HttpSession :request.getSession();

	@Controller
	public class Controller{
		@RequestMapping("/test")
		public String test(HttpSession session){
			String username = request.getParameter("username");
			String age = request.getParameter("age");
			session.setAttribute("username",username);
		
			return "success";
		}
	}
  1. 使用@SessionAttributes
	@Controller
	@SessionAttributes("sessionmap")
	public class Controller{
		@RequestMapping("/test")
		public String test(HttpSession session,ModelMap map){
			String username = request.getParameter("username");
			String age = request.getParameter("age");
			session.setAttribute("username",username);
			map.addAttribute("sessionmap",age);
			return "success";
		}
	}

页面中 指定session作用域中

${sessionScope.sessionmap}

@SessionAttributes()的小括号中如果是一个值,不要加{}
示例:
@SessionAttributes(“key”)
@SessionAttributes({“key1”,“key2”})
用注解SessionAttributes,如果想要清除.需要使用工具类SessionStatus

@RequestMapping("/logoff")
public String logoff(SessionStatus status){
	status.setComplete();
	return "logoff";
}

弹窗响应

例如登出账户

@RequestMapping("/logoff")
public void logoff(SessionStatus status,HttpServletResponse response){
	status.setComplete();
	response.setContentType("text/html;charset=utf-8");
	try{
		PrintWtriter writer = response.getWriter();
		writer.print("<script> alert('登出成功');location.href='logoff.jsp'</scrpit>")
	}catch(IOException e){
		e.printStackTrace();
	}
}

乱码处理

前端页面需要进行编码配置

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

在web.xml文件中加入过滤器

<filter>
    <filter-name>charset</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>
  </filter>
  <filter-mapping>
    <filter-name>charset</filter-name>
    <url-pattern>/*</url-pattern>
    
  </filter-mapping>

转发和重定向

spring mvc中默认转发实现跳转页面

@RequestMapping("/forwardView")
public String forwardView(){
	return "success";
}

重定向分为重定向到新的页面或一个请求

@RequestMapping("/forwardView")
public String forwardView(){
	return "redirect:/success.jsp";//重定向时会忽略视图解析器的配置
}

重定向时地址栏会拼接modelmap中值的问题
解决方法:在重定向时避免使用modelmap的存值方式

异常处理

  1. 配置新的错误页面

    <error-page>
    <error>404</error>
    <location>/404.html</location>
    </error-page>
    
  2. 局部异常
    只能捕捉当前类中的异常

@EexceptionHandler(Exception.class)
public String error(){
 	System.out.println("异常发生");
 	return "error";
}

3.全局异常
创建一个异常工具类,可以捕获不同Controller中的异常

@ControllerAdvice
public class ExceptionController{
	@ExceptionHandler(NullPointerException.class)
	public String error(){
		System.out.println("空指针异常发生");
		return "error";
	}
	@ExceptionHandler(value=UsersException.class)
    public ModelAndView exception1(Exception e){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("msg",e.getMessage());
        modelAndView.setViewName("userError");
        return modelAndView;
    }
}

Cookie操作

//@CookieValue注解可以获取请求中的cookie
//@RequestHandler获取请求头信息中的Accept-Language信息
public String testCookie(@CookieValue("JSESSIONID")String cookie,@RequestHandler("Accept-Language") String language)
{
	System.out.println("cookie:"+cookie);
	System.out.println("language:"+language);
	session
	return "result";
	
}

RestFul风格

REST:即Representational State Transfer ,(资源)表现层状态转化,是目前最流行的一种互联网软件架构。
它们分别代表着四种基本操作:

  • GET用来获取资源 安全 幂等
  • POST用来创建新资源 不安全 幂不等
  • PUT用来更新资源 不安全幂等
  • DELETE用来删除资源 不安全 幂等
    HTTP中对于不同方法规定了不同的安全特性和幂等特性
    这里的安全特性不是传统意义的“安全”,安全特性指资源的状态的改变,在经过多次调取资源的状态仍保持一致,那么则成为安全。
    幂等特性指的是经过多次结果返还,结果值是否能保持一致,如果一致则幂等否则成为幂不等

HiddenHttpMethodFilter:浏览器form表单只支持GET和POST,不支持DELETE和PUT请求,Spring添加了一个过滤器,可以将这些请求转换为标准的http方法,支持GET,POST,DELETE,PUT请求!

  1. 添加过滤器
<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>
  1. 添加控制器
@Controller
public class RestController {
    @RequestMapping(value="/testrest",method = RequestMethod.GET)
    public String get(){
        System.out.println("get请求");
        return "getsuccess";
    }
    @RequestMapping(value="/testrest",method = RequestMethod.POST)
    public String post(){
        System.out.println("post请求");
        return "postsuccess";
    }
    @RequestMapping(value="/testrest",method = RequestMethod.PUT)
    public String put(){
        System.out.println("put请求");
        return "putsuccess";
    }
    @RequestMapping(value="/testrest",method = RequestMethod.DELETE)
    public String delete(){
        System.out.println("delete请求");
        return "deletesuccess";
    }
}
  1. 表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="/testrest" method="get">
    <input type ="submit" value="get">
</form>

<form action="/testrest" method="post">
    <input type ="submit" value="post">
</form>

<form action="/testrest" method="post">
    <input type="hidden" name = "_method" value="put">
    <input type ="submit" value="put">
</form>

<form action="/testrest" method="post">
    <input type="hidden" name = "_method" value="delete">
    <input type ="submit" value="delete">
</form>
</body>
</html>

@PathVriable获取路径参数

@RequestMapping("/user/{name}/{id}")
public String getData(@PathVariable(value = "id") Integer id,@PathVariable(value="name")String name){
System.out.println("id = " + id,"name = " + name);

return "list" ;
}

静态资源访问

由于DispatcherServlet 设置成/会拦截静态资源,所以在需要对静态资源进行淡出处理

  1. 在springmvc配置文件中添加mvc命名空间
  2. 添加处理标签 (通过依次添加映射地址)
<mvc:annotation-driven /> <!--注解驱动-->
<mvc:resources mapping="/img/**" location="/images/" ></mvc:resources>

或通过以下注解对所有静态资源进行配置

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

JSON数据处理

  1. 添加依赖包

    <dependency>
    	<groupId>com.fasterxml.jackson.core</groupId>
    	<artifactId>jackson-databind</artifactId>
    	<version>2.9.5</version>
    </dependency>
    
  2. 配置文件添加注解驱动

<mvc:annotation-driven/>
  1. 实现代码(方法返回类型前)加入注解@ResponseBody将返回值类型转化为JSON格式

SpringMVC拦截器

拦截器interceptor的作用是拦截指定的用户请求,并对其执行相应的预处理和后处理
拦截器发生在handlermapping请求映射的处理器适配器执行处理器之前

创建自定义拦截器

  1. 创建拦截器类:实现HandlerInterceptor接口
    接口中未实现的方法:
    1. postHandle 拦截器结束执行 该方法在处理器执行结束后执行,若处理器未执行,则也不执行。由于该方法在处理器执行之后执行,可获取处理器的结果ModelAndView并可以对其进行处理(修改其数据或更改跳转地址) 场景:日志
    2. afterCompletion无论是否有异常都执行 在处理器返回值之后,在ModelAndView返回值之后,无法再对其值进行修改 场景:对全局资源的操作。。
    3. preHandle 拦截器开始执行 返回值类型为boolean,若为true则会继续执行拦截器方法,且将afterCompletion放置到方法栈中等待执行。若为false则不执行 场景:登陆验证

  2. spring配置文件中创建拦截器对象
    拦截所有请求

    	<mvc:interceptors>
    		<bean class = "com.java.util.MyInterceptor"></bean>
    	</mvc:interceptors>
    

    拦截指定请求

    <mvc:interceptors>
    	<mvc:interceptor >
    	<mvc:mapping path="/请求名" />
    	<mvc:mapping path="/请求名" />
    	<bean id="my" class="util.MyInterceptor"/>
    	</mvc:interceptor>
    </mvc:interceptors>
    

(1)过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
(2)拦截器:
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。

多个拦截器执行顺序:
过滤器优先开始—>拦截器1开始–>拦截器2开始–>拦截器2结束---->拦截器1结束—>过滤器结束

Spring中文件上传和下载

上传
在SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下不能处理文件上传工作。
如果想使用Spring的文件上传功能,则需要先在上下文中配置MultipartResolver。

  1. 添加依赖包
<dependency>
	<groupId>commons-fileupload</groupId>
	<artifactId>commons-fileupload</artifactId>
	<version>1.3.1</version>
</dependency>
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.4</version>
</dependency>
  1. 配置MultipartResolver:
<mvc:annotation-driven/>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:defaultEncoding="UTF-8"
p:maxUploadSize="9999999"/>
  1. 表单提交方式必须是post形式
enctype="multipart/form-data"
  1. 配置java代码。
@RequestMapping("/upload")
public String saveFile(@RequestParam("name") String name , @RequestParam("file")MultipartFile
file) throws IOException {
	//接收表单提交的数据,包含文件
	System.out.println("name = " + name);
	String path=request.getRealPath("/");
	if (!file.isEmpty())
	{
		file.transferTo(new File(path+"upload/"+file.getOriginalFilename()));
	}
	return "success";
}

下载

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>uploadSuccess</h1>
<img src="uploading/${filename}">
<a href="/download?filename=${filename}" >下载</a>

</body>
</html>

@Controller
public class DownloadController {
    @RequestMapping("/download")
    public ResponseEntity<byte[]> download (HttpServletRequest request, String filename) throws IOException {
        String realPath = request.getRealPath("/uploading");
        String filePath = realPath+"/"+filename;
        //创建http头信息的对象
        HttpHeaders httpHeaders = new HttpHeaders();
        //标记以流的方式做出响应

        httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        //attachment 以附件的形式响应给客户端

        httpHeaders.setContentDispositionFormData("attachment", URLEncoder.encode(filename,"UTF-8"));

        File file = new File(filePath);

        ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),httpHeaders, HttpStatus.CREATED);

        return responseEntity;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值