SpringMVC入门------一文上手SpringMVC框架

        SpringMVC是对Servlet的深层次封装,其架构功能分工明确,注解强大易用,方便整合MyBatis,Hiberate,JPA等其他框架。

        友情提示:阅读本文前需具备一些javaweb相关知识,可参考以下博文进行了解:

​​​​​​搭建一个简单的MVC框架_刚上路DE小白的博客-CSDN博客_mvc框架怎么建立

Spring入门之框架核心----IOC/AOP_刚上路DE小白的博客-CSDN博客

首先了解MVC模式:

        Model-View-Controller:模型--视图--控制器
        Model: 模型层 javaBean 负责数据访问和业务处理 dao service pojo
        View: 视图 JSP技术 负责收集和展示数据
        Controller: 控制器 servlet技术 中间调度
                控制器的工作:
                1、接受客户端的请求(包括请求中携带的数据)
                2、处理请求:调用后台的模型层中的业务逻辑
                3、页面导航:处理完毕给出响应:JSP页面

        下面代码示例为一个简单的SpringMVC案例,不涉及dao层,主要了解SpringMVC的工作机制和如何使用。

1.首先创建一个项目:

        创建maven项目后按照如下图补全目录结构:

SpringMVC入门------一文上手SpringMVC框架_第1张图片

2.在pom文件中添加依赖:



    4.0.0

    com.lxj
    MySpringMVC
    1.0-SNAPSHOT

    
        8
        8
    

    war

    
        
            org.springframework
            spring-webmvc
            5.2.13.RELEASE
        
        
            javax.servlet
            javax.servlet-api
            4.0.1
            provided
        
        
            com.fasterxml.jackson.core
            jackson-core
            2.9.0
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.9.0
        
        
            commons-fileupload
            commons-fileupload
            1.3.1
        
    

    
        
            
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.0
                
                    1.8
                    1.8
                
            
            
            
                org.apache.tomcat.maven
                tomcat7-maven-plugin
                2.2
                
                    /
                    8080
                
            
        
    

 3.创建配置文件:

        首先是Spring的配置文件,在resources文件夹下创建applicationContext.xml:



    
    
    

        然后是SpringMVC的配置文件SpringMVC.xml(注意注释中对相关细节有说明):



    
    
    
    
        
        
    
    
    
    
    

    
    
    


    


    
    
        
        
            
            
            
            
        
        
            
            
            
            
        
        
            
            
        
    
    

    
    
        
        
        
    


注意:我们的项目中将存在两个容器,一个是 Spring 容器,另一个是SpringMVC 容器,Spring 容器通过 ContextLoaderListener 来加载,SpringMVC 容器则通过DispatcherServlet 来加载,这两个容器不一样:

SpringMVC入门------一文上手SpringMVC框架_第2张图片

        4.通过web.xml对spring和springmvc配置:



    
    
        
        contextConfigLocation
        
        classpath:applicationContext.xml
    
    
        org.springframework.web.context.ContextLoaderListener
    

    
    
    
        dispatcherServlet
        org.springframework.web.servlet.DispatcherServlet
        
        
            contextConfigLocation
            classpath:springMVC.xml
        
        
        1
    
    
    
        dispatcherServlet
        /
    
    
    
    
        characterEncodingFilter
        org.springframework.web.filter.CharacterEncodingFilter
        
        
            encoding
            UTF-8
        
        
        
            forceRequestEncoding
            true
        
            
            
                forceResponseEncoding
                true
            
    
    
        characterEncodingFilter
        /*
    

    
    
        httpMethodFilter
        
            org.springframework.web.filter.HiddenHttpMethodFilter
        
    
    
        httpMethodFilter
        /*
    

         至此,相关配置文件创建完成,这里对SprngMVC工作流程做简要分析:

SpringMVC入门------一文上手SpringMVC框架_第3张图片

  1. 用户通过浏览器发送请求到前端控制器DispatcherServlet。
  2. 前端控制器直接将请求转给处理器映射器HandleMapping。
  3. 处理器映射器HandleMapping会根据请求,找到负责处理该请求的处理器,并将其封装为处理器执行链HandlerExecutionChina后返回给前端控制器DispatcherServlet。
  4. 前端控制器DispatcherServlet根据处理器执行链中的处理器,找到能够执行该处理器的处理器适配器HandlerAdaptor。
  5. 处理器适配器HandlerAdaptor调用执行处理器Controller。
  6. 处理器Controller将处理结果及要跳转的视图封装到一个对象 ModelAndView 中,并将其返回给处理器适配器HandlerAdaptor。
  7. 处理器适配器直接将结果返回给前端控制器DispatcherServlet。
  8. 前端控制器调用视图解析器,将 ModelAndView 中的视图名称封装为视图对象。
  9. 视图解析器ViewResolver将封装了的视图View对象返回给前端控制器DispatcherServlet.
  10. 前端控制器DispatcherServlet调用视图对象,让其自己进行渲染,即进行数据填充,形成响应对象。
  11. 前端控制器响应浏览器

下面对不同功能逐步进行介绍:

1.不同类型的参数获取:

        新建一个实体类:

package com.lxj.pojo.com.lxj;

import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

public class Team {
    private Integer teamId;
    private  String teamName;
    private String location;
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date createTime;

    @Override
    public String toString() {
        return "Team{" +
                "teamId=" + teamId +
                ", teamName='" + teamName + '\'' +
                ", location='" + location + '\'' +
                ", createTime=" + createTime +
                '}';
    }

    public Integer getTeamId() {
        return teamId;
    }

    public void setTeamId(Integer teamId) {
        this.teamId = teamId;
    }

    public String getTeamName() {
        return teamName;
    }

    public void setTeamName(String teamName) {
        this.teamName = teamName;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}

        新建hello.jsp页面:

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2022/6/5
  Time: 21:49
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Hello


    

8、获取集合类型的参数

球队名称1:
球队名称2:
球队名称3:
球队id1:
球队id2:
球队id3:
球队名称1:
球队名称2:
球队名称3:

7、获取数组类型的参数

球队名称1:
球队名称2:
球队名称3:

6、获取日期类型的参数

球队id:
球队名称:
球队位置:
创建日期:
控制器ParamController.java

5、直接使用URL地址传参

4、使用HttpServletRequest 对象获取参数

球队id:
球队名称:
球队位置:

3、请求参数和方法名称的参数不一致

球队id:
球队名称:
球队位置:

2、使用对象接收多个参数

球队id:
球队名称:
球队位置:

1、直接使用方法的参数逐个接收

球队id:
球队名称:
球队位置:

        新建对应的controlor:

package com.lxj.controller;

import com.lxj.pojo.com.lxj.QueryVO;
import com.lxj.pojo.com.lxj.Team;
import com.lxj.service.TeamService;
import org.springframework.beans.factory.annotation.Autowired;
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;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Controller
@RequestMapping("param")
public class TeamController {
    @Autowired
    TeamService teamService;

    /**
    * 1、直接使用方法的参数逐个接收:方法的参数名称必须与用户请求中携带的参数名称保持一致,否则
        就获取不到
    * 好处:不需要类型转换
    */
    @RequestMapping("test01")
    public ModelAndView test01(Integer teamId,String teamName,String
            teamLocation){
        System.out.println("test01-----------------");
        System.out.println(teamId);
        System.out.println(teamName);
        System.out.println(teamLocation);
        return new ModelAndView("ok");
    }
    //2、使用对象接收多个参数:要求用户请求中携带的参数名称必须是实体类中的属性保持一致,否则就获取不到
    @RequestMapping("test02")
    public ModelAndView test02(Team team){
        System.out.println("test02-----------------");
        System.out.println(team);
        return new ModelAndView("ok");
    }
    //3、请求参数和方法名称的参数不一致:使用@RequestParam进行矫正,
    // value属性表示请求中的参数名称
    // required属性表示参数是否是必须的:true:必须赋值,否则报出400错;false:可以不赋值,结果就是null
    @RequestMapping("test03")
    public ModelAndView test03(@RequestParam(value = "teamId",required = false)
                                       Integer id,
                               @RequestParam(value = "teamName",required = true)
                                       String name,
                               @RequestParam("location") String loc){
        System.out.println("test03-----------------");
        System.out.println(id);
        System.out.println(name);
        System.out.println(loc);
        return new ModelAndView("ok");
    }

    //4、使用HttpServletRequest 对象获取参数:跟原来的javaWeb项目中使用的方式是一样的
    @RequestMapping("test04")
    public ModelAndView test04(HttpServletRequest request){
        System.out.println("test04-----------------");
        String teamId = request.getParameter("teamId");
        String teamName = request.getParameter("teamName");
        String location = request.getParameter("location");
        if(teamId!=null)
            System.out.println(Integer.valueOf(teamId));
        System.out.println(teamName);
        System.out.println(location);
        return new ModelAndView("ok");
    }
    //5、直接使用URL地址传参: 借助@PathVariable 注解
    // 例如http://localhost:8080/param/test05/1001/lacker/las
    @RequestMapping("test05/{id}/{name}/{loc}")
    public ModelAndView test05(@PathVariable("id") Integer teamId,
                               @PathVariable("name") String teamName,
                               @PathVariable("loc") String teamLocation){
        System.out.println("test05-----------------");
        System.out.println(teamId);
        System.out.println(teamName);
        System.out.println(teamLocation);
        return new ModelAndView("ok");
    }

    //6、获取日期类型的参数
    @RequestMapping("test06")
    public ModelAndView test06(Team team){
        System.out.println("test06-----------------");
        System.out.println(team);
        return new ModelAndView("ok");
    }
    //7、获取数组类型的参数
    @RequestMapping("test07")
    public ModelAndView test07(String[] teamName,HttpServletRequest request){
        System.out.println("test07-----------------");
        //方式1:
        for (String s : teamName) {
            System.out.println(s);
        } System.out.println("---------------");
        //方式2:
        String[] teamNames = request.getParameterValues("teamName");
        for (String name : teamNames) {
            System.out.println(name);
        }
        return new ModelAndView("ok");
    }

    //8、获取集合类型的参数: 简单类型的可以通过@RequestParam注解实现;对象集合不支持直接获取,必须封装在类中,作为一个属性操作
    @RequestMapping("test08")
    public ModelAndView test08(@RequestParam("teamName") List nameList){
        System.out.println("test08-----------------");
        for (String s : nameList) {
            System.out.println(s);
        }
        return new ModelAndView("ok");
    }
    @RequestMapping("test09")
    public ModelAndView test09(QueryVO vo){
        System.out.println("test09-----------------");
        for (Team team : vo.getTeamList()) {
            System.out.println(team);
        }
        return new ModelAndView("ok");
    }

    @RequestMapping("Hello.do")
    public ModelAndView add(){
        System.out.println("TeamController:add()");
        teamService.add();
        ModelAndView mv=new ModelAndView();
        mv.addObject("teamName","湖人");//相当于request.setAttrubuite("teanName","湖人");
        mv.setViewName("index");//未来经过springmvc的视图解析器处理,转换成物理资源路径,相当于request.getRequestDispatcher("index.jsp").forward();
        //经过InternalResourceViewResolver对象的处理之后加上前后缀就变为了/jsp/index.jsp
        return mv;
    }
}

遇到中午乱码问题,可在web.xml中添加字符集过滤器(详见上文web.xml中)

2.不同类型的返回值

        新建result.jsp:

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2022/6/6
  Time: 20:24
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    result
    


    

result----------------

test01------${teamName}---

test02---request作用域获取:---${requestScope.team.teamName}-- -${requestScope.team.teamId}---${requestScope.team.location}

test02---session作用域获取:---${sessionScope.team.teamName}-- -${sessionScope.team.teamId}---${sessionScope.team.location}

ajax请求自定义对象的结果展示

ajax请求自定义对象的结果展示

ajax请求Map的结果展示

        新建对应的controllor:

package com.lxj.controller;

import com.lxj.pojo.com.lxj.Team;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

@Controller
@RequestMapping("result")
public class ResultController {
    //1、返回值是ModelAndView: 这种方式既有数据的携带还有资源的跳转,可以选择该种方式
    @RequestMapping("test01")
    public ModelAndView test01(){
        ModelAndView mv=new ModelAndView();//模型与视图
        //携带数据
        mv.addObject("teamName","湖人队");//相当于request.setAttribute("teamName","湖人队“);
        mv.setViewName("result");// 经过视图解析器InternalResourceViewResolver的处理,将逻辑视图名称加上前后缀变为物理资源路径 /jsp/result.jsp
        return mv;
    }
    //2、返回字符串
    @RequestMapping("test02")
    public String test02(HttpServletRequest request){
        Team team=new Team();
        team.setLocation("迈阿密");
        team.setTeamId(1002);
        team.setTeamName("热火");
        //携带数据
        request.setAttribute("team",team);
        request.getSession().setAttribute("team",team);
        //资源的跳转
        return "result";// 经过视图解析器InternalResourceViewResolver的处理,将逻辑视图名称加上前后缀变为物理资源路径 /jsp/result.jsp
    }
    //3、返回对象类型:Integer Double String 自定义类型 List Map 返回的不是逻辑视图的名称,而直接就是数据返回 ,一般是ajax请求搭配使用 ,将json格式的数据直接返回给响应体一定要与@ResponseBody
    @ResponseBody
    @RequestMapping("test03-1")
    public Integer test031(){
        return 666;
    }
    @ResponseBody
    @RequestMapping("test03-2")
    public String test032(){
        return "test";
    }
    @ResponseBody
    @RequestMapping("test03-3")
    public Team test033(){
        Team team=new Team();
        team.setLocation("迈阿密");
        team.setTeamId(1002);
        team.setTeamName("热火");
        return team;
    }

    @ResponseBody
    @RequestMapping("test03-4")
    public List test034(){
        List list=new ArrayList<>(5);
        for(int i=1;i<=5;i++) {
            Team team = new Team();
            team.setLocation("迈阿密"+i);
            team.setTeamId(1002+i);
            team.setTeamName("热火"+i);
            list.add(team);
        }
        return list;
    }

    @ResponseBody
    @RequestMapping("test03-5")
    public Map test035(){
        Map map=new HashMap();
        for(int i=1;i<=5;i++) {
            Team team = new Team();
            team.setLocation("金州"+i);team.setTeamId(1000+i);
            team.setTeamName("勇士"+i);
            //日期类型,在返回的时候是个数字,如果想要按日期格式展示需要在实体类对应属性添加注解@JsonFormat(pattern = "yyyy-MM-dd")
            team.setCreateTime(new Date());
            map.put(team.getTeamId()+"",team);
        }
        return map;
    }

    //通过 HttpServletRequest 做服务端跳转
    @RequestMapping("test04-1")
    public void test041(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        System.out.println("直接使用HttpServletRequest进行服务器端的转发");
        request.getRequestDispatcher("/jsp/ok.jsp").forward(request,response);
    }

    //通过 HttpServletResponse 做重定向
    @RequestMapping("test04-2")
    public void test042(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        System.out.println("直接使用HttpServletResponse重定向跳转");
        response.sendRedirect("/jsp/ok.jsp");
    }

    //通过 HttpServletResponse 给出响应
    @RequestMapping("test04-3")
    public void test043(HttpServletResponse response) throws ServletException,
            IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write("返回void类型测试---直接返回字符串");
        writer.flush();
        writer.close();
    }

    //也可以自己手动指定响应头去实现重定向:
    @RequestMapping("test04-4")
    public void test044(HttpServletResponse response) throws ServletException,
            IOException {
        response.setStatus(302);//设置响应码,302表示重定向
        response.setHeader("Location","/jsp/ok.jsp");
    }

}

3.转发和重定向:

package com.lxj.controller;

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

import javax.servlet.http.HttpServletRequest;

@Controller
@RequestMapping("navigation")
public class NavigationController {

    @RequestMapping("test01-1")
    public String test011(HttpServletRequest request){
        request.setAttribute("teamName","湖人");
        //return "ok";//默认方式:由视图解析器处理之后将逻辑视图转为物理资源路径
        return "forward:/jsp/ok.jsp";//当添加了forward前缀之后,视图解析器中的前后缀就失效了,必须自己编写绝对路径
    }

    @RequestMapping("test01-2")
    public ModelAndView test012(){
        ModelAndView mv=new ModelAndView();
        mv.addObject("teamName","热火");
        //mv.setViewName("ok");//默认方式:由视图解析器处理之后将逻辑视图转为物理资源路径
        mv.setViewName( "forward:/jsp/ok.jsp");//当添加了forward前缀之后,视图解析器中的前后缀就失效了,必须自己编写绝对路径
        return mv;
    }

    @RequestMapping("test02-1")
    public String test021(HttpServletRequest request){
        request.setAttribute("teamName","勇士");//页面上无法获取到存储在request作用域中的值,请求中断了
        return "redirect:/jsp/ok.jsp";//当添加了redirect前缀之后,视图解析器中的前后缀就失效了,必须自己编写绝对路径
    }

    @RequestMapping("test02-2")
    public ModelAndView test022(){
        ModelAndView mv=new ModelAndView();
        mv.addObject("teamName","huangfeng");
        //存储在request作用域中的值以参数的形式追加在URL后面
        http://localhost:8080/jsp/ok.jsp?teamName=huangfeng&teamId=1002
        mv.addObject("teamId","1002");
        mv.setViewName( "redirect:/jsp/ok.jsp");//当添加了redirect前缀之后,视图解析器中的前后缀就失效了,必须自己编写绝对路径
        return mv;
    }
}

4.异常处理:

        首先自定义不同级别的异常类:

package com.lxj.exception;

public class TeamException extends Exception{
    public TeamException() {
    }
    public TeamException(String message) {
        super(message);
    }
}
package com.lxj.exception;

public class TeamIdException extends TeamException{
    public TeamIdException() {
    }
    public TeamIdException(String message) {
        super(message);
    }
}
package com.lxj.exception;

public class TeamNameException extends TeamException{
    public TeamNameException() {
    }
    public TeamNameException(String message) {
        super(message);
    }
}

        编写对应的controller:

package com.lxj.controller;

import com.lxj.exception.TeamIdException;
import com.lxj.exception.TeamNameException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("exp")
public class ExController {

    @RequestMapping("test01/{id}/{name}")
    public ModelAndView test01(@PathVariable("id") Integer teamId, @PathVariable("name") String teamName)
            throws TeamIdException,TeamNameException {
        ModelAndView mv=new ModelAndView();
        if(teamId<=1000){
            throw new TeamIdException("teamId不合法!必须在1000之上!");
        }
        if("test".equals(teamName)){
            throw new TeamNameException("teamName不合法!不能使用test!");
        }
        System.out.println(10/0);
        mv.setViewName("ok");
        return mv;
    }

    @ExceptionHandler(value = {TeamIdException.class,TeamNameException.class,Exception.class})
    public ModelAndView exHandler(Exception ex){
        ModelAndView mv=new ModelAndView();
        mv.addObject("msg",ex.getMessage());
        if(ex instanceof TeamIdException)
            mv.setViewName("idError");
        else if(ex instanceof TeamNameException)
            mv.setViewName("nameError");
        else
            mv.setViewName("error");
        return mv;
    }
}

package com.lxj.exception;

import com.lxj.exception.TeamException;
import com.lxj.exception.TeamIdException;
import com.lxj.exception.TeamNameException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(value = TeamIdException.class)
    public ModelAndView exHandler1(Exception ex){
        ModelAndView mv=new ModelAndView();
        mv.addObject("msg",ex.getMessage());
        mv.setViewName("idError");
        return mv;
    }
    @ExceptionHandler(value = TeamNameException.class)
    public ModelAndView exHandler2(Exception ex){
        ModelAndView mv=new ModelAndView();
        mv.addObject("msg",ex.getMessage());
        mv.setViewName("nameError");
        return mv;
    }

    @ExceptionHandler(value = TeamException.class)
    public ModelAndView exHandler4(Exception ex){
        ModelAndView mv=new ModelAndView();
        mv.addObject("msg",ex.getMessage());
        mv.setViewName("nameError");
        return mv;
    }
    @ExceptionHandler(value = Exception.class)
    public ModelAndView exHandler3(Exception ex){
        ModelAndView mv=new ModelAndView();
        mv.addObject("msg",ex.getMessage());
        mv.setViewName("error");
        return mv;
    }

}

        分别写error.jsp/iderror.jsp/nameerror.jsp进行实验:

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2022/6/13
  Time: 20:40
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    error


    

默认的错误页面--${msg}

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2022/6/13
  Time: 20:40
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    teamId


    

teamId Error----${msg}

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2022/6/13
  Time: 20:41
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    teamName


    

teamName error---${msg}

5.拦截器:

        SpringMVC 中的 拦截器( Interceptor)是非常重要的,它的主要作用是拦截指定的用户请求,并进行相应的预处理与后处理。拦截的时间点在“处理器映射器HandlerMapping根据用户提交的请求映射出了所要执行的处理器类,并且也找到了要执行该处理器类的处理器适配器,在处理器适配器HandlerAdaptor执行处理器之前”。在处理器映射器映射出所要执行的处理器类时,已经将拦截器与处理器组合为了一个处理器执行链HandlerExecutionChain,并返回给了前端控制器。自定义拦截器,需要实现 HandlerInterceptor 接口。而该接口中含有三个方法:

preHandle(request,response, Object handler):
        该方法在处理器方法执行之前执行。其返回值为boolean,若为true,则紧接着会执行处理器方法,且会将afterCompletion()方法放入到一个专门的方法栈中等待执行。
postHandle(request,response, Object handler,modelAndView):
        该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。由于该方法是在处理器方法执行完后执行,且该方法参数中包含 ModelAndView,所以该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。
afterCompletion(request,response, Object handler, Exception ex):
        当 preHandle()方法返回true时,会将该方法放到专门的方法栈中,等到对请求进行响应的所工作完成之后才执行该方法。即该方法是在前端控制器渲染(数据填充)了响应页面之后执行的,此时对ModelAndView再操作也对响应。

        首先自定义拦截器:

package com.lxj.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class MyInterceptor implements HandlerInterceptor {
    //执行时间: 控制器方法执行之前,在ModelAndView返回之前
    //使用场景: 登录验证
    // 返回值 true : 继续执行控制器方法 表示放行 false: 不会继续执行控制器方法,表示拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle---------------------");
        return true;
    }
    //执行时间: 控制器方法执行之hou后,在ModelAndView返回之前,有机会修改返回值
    //使用场景: 日记记录,记录登录的ip,时间
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle---------------------");
    }
    //执行时间: 控制器方法执行之后,在ModelAndView返回之后,没有机会修改返回值
    //使用场景: 全局资源的一些操作
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion----------------------");
    }
}
package com.lxj.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class MyInterceptor2 implements HandlerInterceptor {
    //执行时间: 控制器方法执行之前,在ModelAndView返回之前
    //使用场景: 登录验证
    // 返回值 true : 继续执行控制器方法 表示放行 false: 不会继续执行控制器方法,表示拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle2---------------------");
        return true;
    }
    //执行时间: 控制器方法执行之hou后,在ModelAndView返回之前,有机会修改返回值
    //使用场景: 日记记录,记录登录的ip,时间
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle2---------------------");
    }
    //执行时间: 控制器方法执行之后,在ModelAndView返回之后,没有机会修改返回值
    //使用场景: 全局资源的一些操作
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion2----------------------");
    }
}

        然后在springmvc.xm中进行配置(详见前文配置文件)

6.文件上传和下载

        首先添加依赖,并在springmvc.xml中配置


    commons-fileupload
    commons-fileupload
    1.3.1


        在项目中添加文件夹保存上传的文件:

SpringMVC入门------一文上手SpringMVC框架_第4张图片

         添加fileHandle.jsp文件:

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2022/6/14
  Time: 21:04
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    文件操作


    
请选择文件:

        新建controller:

package com.lxj.controller;

import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.UUID;

@Controller
@RequestMapping("file")
public class FileController {
    @RequestMapping("upload")
    public String upload(@RequestParam("myFile") MultipartFile myFile,
                         HttpServletRequest request){
        //获取文件的原始名称 d:\te.aa\txcat.jpg
        String originalFilename = myFile.getOriginalFilename();
        // 实际开发中,一般都要将文件重新名称进行存储
        // 存储到服务器的文件名称=随机的字符串+根据实际名称获取到源文件的后缀
        String fileName= UUID.randomUUID().toString().replace("-","")
                +originalFilename.substring(originalFilename.lastIndexOf("."));
        System.out.println(fileName);
        //文件存储路径
        String realPath = request.getServletContext().getRealPath("/uploadFile")+"/";
        try {
            myFile.transferTo(new File(realPath+fileName));//真正的文件上传到服务器指定的位置
            System.out.println("上传成功!"+realPath+fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "ok";
    }

    @RequestMapping("download")
    public ResponseEntity download(HttpServletRequest request) throws IOException {
        String path=request.getServletContext().getRealPath("/uploadFile")+"/9078a8f8d2f148629136f3f03133631e.png";
        //创建响应 的头信息的对象
        HttpHeaders headers=new HttpHeaders();
        //标记以流的方式作出响应
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        //以附件的形式响应给用户
        headers.setContentDispositionFormData("attachment", URLEncoder.encode("9078a8f8d2f148629136f3f03133631e.png","utf-8"));
        File file=new File(path);
        ResponseEntity resp=new ResponseEntity<>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);
        return resp;
    }

    @RequestMapping("hello")
    public String hello(){
        return "fileHandle";
    }
}

        文件过滤器:

package com.lxj.interceptor;

import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import java.util.Map;

public class FileInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean flag=true;
        if (request instanceof MultipartHttpServletRequest) {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            Map fileMap = multipartRequest.getFileMap();
            //遍历文件
            Iterator iterator = fileMap.keySet().iterator();
            while (iterator.hasNext()) {
                String key = iterator.next();
                MultipartFile file = multipartRequest.getFile(key);
                String originalFilename = file.getOriginalFilename();
                String hz = originalFilename.substring(originalFilename.lastIndexOf("."));
                //判断后缀是否合法
                if (!hz.toLowerCase().equals(".png") && !hz.toLowerCase().equals(".jpg")) {
                    request.getRequestDispatcher("/jsp/fileTypeError.jsp").forward(request, response);
                    flag = false;
                }
            }
        }
        return flag;
    }
}

7.RESTful风格:

        不强制,但强烈建议。

        主要是用GET、POST、PUT、DELETE。他们分别对应四种基本操作:GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。

创建restful.jsp:

<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2022/6/6
  Time: 20:24
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    result
    


    

result----------------

test01------${teamName}---

test02---request作用域获取:---${requestScope.team.teamName}-- -${requestScope.team.teamId}---${requestScope.team.location}

test02---session作用域获取:---${sessionScope.team.teamName}-- -${sessionScope.team.teamId}---${sessionScope.team.location}

ajax请求自定义对象的结果展示

ajax请求自定义对象的结果展示

ajax请求Map的结果展示

        这里需要注意:在Ajax中,采用Restful风格PUT和DELETE请求传递参数无效,传递到后台的参数值为null,前端页面中的ajax发送请求的时候在url中加 &_method=”PUT” 或者 &_method=”DELETE” 即可。

        自己封装一个公用的响应结果实体类:

package com.lxj.pojo.com.lxj;

import java.util.List;

public class AjaxResultVo {
    private Integer code;
    private String msg;
    private List list;
    private T obj;

    public AjaxResultVo(){
        code=200;
        msg="ok";
        list=null;
        obj=null;
    }

    public AjaxResultVo(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public AjaxResultVo(Integer code, String msg, List list) {
        this.code = code;
        this.msg = msg;
        this.list = list;
    }

    public AjaxResultVo(Integer code, String msg, T obj) {
        this.code = code;
        this.msg = msg;
        this.obj = obj;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

        新建控制器:

package com.lxj.controller;

import com.lxj.pojo.com.lxj.Team;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.*;

@Controller
@RequestMapping("result")
public class ResultController {
    //1、返回值是ModelAndView: 这种方式既有数据的携带还有资源的跳转,可以选择该种方式
    @RequestMapping("test01")
    public ModelAndView test01(){
        ModelAndView mv=new ModelAndView();//模型与视图
        //携带数据
        mv.addObject("teamName","湖人队");//相当于request.setAttribute("teamName","湖人队“);
        mv.setViewName("result");// 经过视图解析器InternalResourceViewResolver的处理,将逻辑视图名称加上前后缀变为物理资源路径 /jsp/result.jsp
        return mv;
    }
    //2、返回字符串
    @RequestMapping("test02")
    public String test02(HttpServletRequest request){
        Team team=new Team();
        team.setLocation("迈阿密");
        team.setTeamId(1002);
        team.setTeamName("热火");
        //携带数据
        request.setAttribute("team",team);
        request.getSession().setAttribute("team",team);
        //资源的跳转
        return "result";// 经过视图解析器InternalResourceViewResolver的处理,将逻辑视图名称加上前后缀变为物理资源路径 /jsp/result.jsp
    }
    //3、返回对象类型:Integer Double String 自定义类型 List Map 返回的不是逻辑视图的名称,而直接就是数据返回 ,一般是ajax请求搭配使用 ,将json格式的数据直接返回给响应体一定要与@ResponseBody
    @ResponseBody
    @RequestMapping("test03-1")
    public Integer test031(){
        return 666;
    }
    @ResponseBody
    @RequestMapping("test03-2")
    public String test032(){
        return "test";
    }
    @ResponseBody
    @RequestMapping("test03-3")
    public Team test033(){
        Team team=new Team();
        team.setLocation("迈阿密");
        team.setTeamId(1002);
        team.setTeamName("热火");
        return team;
    }

    @ResponseBody
    @RequestMapping("test03-4")
    public List test034(){
        List list=new ArrayList<>(5);
        for(int i=1;i<=5;i++) {
            Team team = new Team();
            team.setLocation("迈阿密"+i);
            team.setTeamId(1002+i);
            team.setTeamName("热火"+i);
            list.add(team);
        }
        return list;
    }

    @ResponseBody
    @RequestMapping("test03-5")
    public Map test035(){
        Map map=new HashMap();
        for(int i=1;i<=5;i++) {
            Team team = new Team();
            team.setLocation("金州"+i);team.setTeamId(1000+i);
            team.setTeamName("勇士"+i);
            //日期类型,在返回的时候是个数字,如果想要按日期格式展示需要在实体类对应属性添加注解@JsonFormat(pattern = "yyyy-MM-dd")
            team.setCreateTime(new Date());
            map.put(team.getTeamId()+"",team);
        }
        return map;
    }

    //通过 HttpServletRequest 做服务端跳转
    @RequestMapping("test04-1")
    public void test041(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        System.out.println("直接使用HttpServletRequest进行服务器端的转发");
        request.getRequestDispatcher("/jsp/ok.jsp").forward(request,response);
    }

    //通过 HttpServletResponse 做重定向
    @RequestMapping("test04-2")
    public void test042(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        System.out.println("直接使用HttpServletResponse重定向跳转");
        response.sendRedirect("/jsp/ok.jsp");
    }

    //通过 HttpServletResponse 给出响应
    @RequestMapping("test04-3")
    public void test043(HttpServletResponse response) throws ServletException,
            IOException {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = response.getWriter();
        writer.write("返回void类型测试---直接返回字符串");
        writer.flush();
        writer.close();
    }

    //也可以自己手动指定响应头去实现重定向:
    @RequestMapping("test04-4")
    public void test044(HttpServletResponse response) throws ServletException,
            IOException {
        response.setStatus(302);//设置响应码,302表示重定向
        response.setHeader("Location","/jsp/ok.jsp");
    }

}

        本文是学习了 “开课吧JAVAEE开发工程师” 课程相关内容后结合课堂笔记和代码总结的,如有意愿和兴趣进行更全面的学习和提升可参加开课吧相关课程培训学习:JavaEE商业项目架构就业班-开课吧

你可能感兴趣的:(JAVA,mvc,servlet,java)