SpringMVC

SpringMVC概述

springMVC是spring框架的一个模块,springMVC和spring无需通过中间整合层进行整合

springmvc是一个基于mvc的web框架,方便前后端数据的传输

SpringMVC拥有控制器,接收外部请求,解析参数传给服务层

SpringMVC运行流程

 

1.用户向服务器发送请求,请求被Spring前端控制ServeltDispatcherServlet捕获;

2.前端控制器DispatcherServlet接收请求后,调用处理器映射HandlerMapping

处理器映射器HandlerMapping根据请求的url找到处理该请求的处理器Handler(即Controller),将处理器Handler返回给前端控制器DispatcherServlet

3.DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapter。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:

HttpMessageConveter:将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息

数据转换:对请求消息进行数据转换。如String转换成Integer、Double等

数据根式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等

数据验证:验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中

4.Handler(自己的控制器)执行完成后,向DispatcherServlet返回一个ModelAndView对象

5.根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet

6.ViewResolver结合Model和View,来渲染视图

7.将渲染结果返回给客户端

SpringMVC组件

DispatcherServlet

Spring中提供了org.springframework.web.servlet.DispatcherServlet类,它从HttpServlet继承而来,它就是SpringMVC中的前端控制器(Frontcontroller)

HandlerMapping

DispatcherServlet自己并不处理请求,而是将请求交给页面控制器。那么在DispatcherServlet中如何选择正确的页面控制器呢?这件事情就交给HandlerMapping来做了,经过了HandlerMapping处理之后,DispatcherServlet就知道要将请求交给哪个页面控制器来处理了

HandlerAdapter

经过了HandlerMapping处理之后,DispatcherServlet就获取到了处理器,但是处理器有多种,为了方便调用,DispatcherServlet将这些处理器包装成处理器适配器HandlerAdapter,HandlerAdapter调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名)

搭建SpringMVC

导包

<!-- SpringMVC -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.2.2.RELEASE</version>
</dependency>       

配置DispatcherServlet

在web.xml文件中配置DispatcherServlet

配置spring核心请求分发器

  <!--
       springmvc中提供的一个对servlet进行封装的请求分发Servlet
    -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--配置一个初始化参数, 参数spring配置文件-->
        <init-param>
            <param-name>contextConfigLocation</param-name><!--名字固定-->
            <param-value>classpath:spring.xml</param-value><!--配置spring配置文件-->
        </init-param>
        <!--服务器启动时创建servlet-->
        <load-on-startup>0</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!-- / 所有请求都会进入到DispatcherServlet-->
        <url-pattern>/</url-pattern> 
    </servlet-mapping>

开启SpringMVC注解

<!--开启springmvc注解-->
<mvc:annotation-driven></mvc:annotation-driven>

控制器类搭建

新建一个controller包,这个包就相当于之前的servlet包,只是在不同的java框架中我们给定的名字不同。

再建一个Controller类,编写代码

@Controller 用于标记在一个类上,使用它标记的类就是一个 SpringMVC Controller 对象

spring配置中指定了自动扫描的basepackage后,spring会扫描这些包中使用了@Controller 标识的类,然后将类加入到springIOC容器中添加依赖

@RequestMapping 注解是一个用来处理请求地址映射的注解,可用于类或方法上

//@Controller  表示此类是控制层类。spring生成对象,方法返回值,默认是jsp的解析方式
@RequestMapping(path = "/admin/loginCtl")
public class LoginController {
​
}

接收请求

@RequestMapping

它的作用就是与请求相匹配,如果匹配上了,所修饰的方法才会被执行。这里我们只需要关注两个属性:

value

请求的路径,这个路径相对于应用的上下文,它是path的别名。类型是一个String[],也就是说它可以匹配多个请求路径

method

请求的方法。我们知道HTTP协议的请求方式有GET和POST.或者使用@GetMapping,@PostMapping

当前的请求只有与@RequestMapping上指定的属性都匹配的时候,才会执行它标注的方法。

案例

前端

<body>
  <a href="admin/getAdmin?id=1&name='zhangsan'">admin</a>
​
  <form method="post" action="admin/getAdmin">
      账号:<input type="text" name="account">
      密码:<input type="text" name="password">
      年龄:<input type="text" name="age">
      生日:<input type="text" name="birthday">
       <input type="submit">
  </form>
</body>

后端

//@Controller  表示此类是控制层类。spring生成对象,方法返回值,默认是jsp的解析方式
@RequestMapping(path = "/admin/loginCtl")//处理请求地址映射的注解
public class LoginController {
​
    @Autowired
    LoginService loginService;
​
    /*
       value path 都是为类和方法指定映射地址. 是一个数组.
       可以配置多个地址,value = {"/test","/test1"}
       method 设置哪些请求方式可以访问此方法 ,如果没有设置,那么所有请求都可以
       也可以使用@PostMapping(value = "/test")  或者 @GetMapping(value = "/test");来指定
       @GetMapping(value = "/test")
       */
       
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    public Admin login(Admin admin){
        System.out.println("login");
        System.out.println(admin);
        Admin a = loginService.login(admin);
        return a;
    }
}

获取请求数据

我们编写处理器方法的目的,就是为了处理客户端提交的数据,而客户端的提交是按照 HTTP 协议报文格式来提交的。

springMVC可以将HttpServletRequest request,HttpServletResponse 直接注入到我们方法中

可以使用 request 对象接受数据

@PostMapping(value = "/login")
    public String login(HttpServletRequest request, HttpServletResponse response, HttpSession session){
        request.getParameter("");
        System.out.println("login");
        return "hellow";
    }

就和servlet一样,在调用时可以获取请求头、请求体等,这里使用注解方式实现

请求头:比如获取 User-Agent 中的值则使用@RequestHeader(“User-Agent”) 来获取

请求参数:比如获取 name 参数的值,则使用@RequestParam(“name”)来获取

 @PostMapping(value = "/login")
    public String login(@RequestHeader("User-Agent") String userAgent,
                        @RequestParam("account") String account,String password){
        System.out.println(userAgent);
        System.out.println(account);
        System.out.println(password);
        return "hellow";
    }

如 果 请 求 参 数 的 名 称 与 处 理 器 方 法 中 的 参 数 名 称 相 同 , 那 么 在 使 用 @RequestParam 绑定的时候,可以省略参数,甚至连@RequestParam 都可以省略

 @GetMapping(path = "/getAdmin")
     public void getAdmin(Integer id,String name){
          System.out.println(id);
          System.out.println(name);
     }

参数绑定与类型转换

如果请求参数比较多,通常是将这些参数放到一个实体中,然后只需要在处理器 方法上定义这个实体作为参数。HandlerAdapter 会将这个对象的实例创建出 来,然后从请求参数中取出这些参数然后放到实体对象中,需要注意的是请求参 数的名字需要与实体类中的属性一一对应,只有对应的属性才会提取参数的值

   @PostMapping(path = "/getAdmin")
     public void getAdmin(Admin admin,Integer flag){
          System.out.println(admin);
     }

可以在日期上添加一个@DateTimeFormat,指定了 Date 类型的格式

@DateTimeFormat(pattern="yyy-MM-dd") 
private Date birthday;

中文乱码处理

SpringMVC 中已经为我们提供了一个过滤器,为 request 对象设置编码集。

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

Ajax返回JSON

@responseBody 注解的作用是将 controller 的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到 response 对象的 body 区,通常用来向异 步请求返回 JSON 数据。

注意:在使用此注解之后不会再走视图处理器,而是直接将数据写入到输入流中,他的效果等同于通过 response 对象输出指定格式的数据

添加 jacksonjar 包

<!-- jackson -->
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.9.1</version>
</dependency>

案例

@Controller
@RequestMapping(path = "/admin")
public class AdminController {
    @PostMapping(path = "/save")
    @ResponseBody
    public Map save(String name, int age, HttpServletResponse response) {
        Map map = new HashMap();
        try {
            map.put("code", 200);
            map.put("data", new ArrayList<>().add("a"));
            map.put("msg", "操作成功");
        } catch (Exception e) {
            map.put("code", 500);
            map.put("msg", "操作失败");
        }
        return map;
    }
}

拦截器

SpringMVC定义了拦截器接口HandlerInterceptor

接口中定义了三个方法,这三个方法的调用在SpringMVC框架内部完成

调用三个方法时,其参数也是从框架内部传过来的

boolean preHandle

预处理方法,实现处理器方法的预处理,就是在处理器方法执行之前这个方法会被执行,相当于拦截了处理器方法,框架会传递请求和响应对象给该方法,第三 个参数为被拦截的处理器方法。如果 preHandle 方法返回 true 表示继续流程(如 调用下一个拦截器或处理器方法),返回 false 表示流程中断,不会继续调用其他的拦截器或处理器方法,此时我们需要通过response 来产生响应

/*
    预处理--进入到控制器之前,
    返回false 不会进入到控制器
    返回true  会进入到控制器
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

void postHandle

后处理方法,实现处理器方法的后处理,就是在处理器方法调用完成,但在渲染视图之前,该方法被调用,此时我们可以通过 modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理

  /*
    控制器执行完成后,执行
     */
   @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
​
    }

afterCompletion

整个请求处理完毕,即在视图渲染完毕时该方法被执行

  /*
    整个请求结束后执行
     */
   @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
​
    }

因为我们调用Ajax返回给服务器,就不会返回ModelAndView,不走流程中的这一步和后面的步骤,所以我们在使用的时候只使用 preHandle

拦截器实现

编写一个类继承HandlerInterceptorAdapter

public class LoginInterceptor implements HandlerInterceptor {
    /*
    预处理--进入到控制器之前,
    返回false 不会进入到控制器
    返回true  会进入到控制器
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        Admin admin = (Admin) session.getAttribute("admin");
        if (admin == null){
            response.getWriter().println("202");
            return false;
        }else {
            return true;
        }
    }
​
}

在spring_mvc.xml中配置拦截器

  <!--配置拦截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 配置所有请求都进入拦截器 -->
            <mvc:mapping path="/**"/>
            <!-- exclude-mapping 配置什么请求不进入拦截器 -->
            <mvc:exclude-mapping path="/login/login"/>
            <mvc:exclude-mapping path="/css/**"/>
            <mvc:exclude-mapping path="/js/**"/>
            <mvc:exclude-mapping path="/images/**"/>
            <mvc:exclude-mapping path="/**.html"/>
            <!-- bean 表示配置的是哪一个拦截器 -->
            <bean id="login" class="com.ffyc.ssm.util.LoginInterceptor"></bean>
        </mvc:interceptor>
        <!-- 其他拦截器... -->
    </mvc:interceptors>

文件上传

导入上传下载所需jar文件

<!-- fileupload -->
   <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.3.3</version>
</dependency>

在spring_mvc.xml 中配置文件解析器

  <!--文件解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"></property>
        <property name="maxUploadSize" value="10485760"></property>
    </bean>

控制器类

 @PostMapping(path = "/upload")
    public CommonResult upload(@RequestParam("file") CommonsMultipartFile file,
                               @RequestHeader("adminToken") String adminToken) {
        CommonResult commonResult = null;
        try {
            DecodedJWT tokenInfo = JWTUtil.getTokenInfo(adminToken);
            int id = tokenInfo.getClaim("id").asInt();
            String account = tokenInfo.getClaim("account").asString();
            String path = "D:\\Program Files\\apache-tomcat-9.0.43\\webapps\\userFile\\"+account;
                   File file1 = new File(path);
                   if (!file1.exists()){
                       file1.mkdir();
                   }
​
            String newfileName = new Date().getTime()+file.getOriginalFilename();
            path+="\\"+newfileName;
            file.transferTo(new File(path));
​
                   //保存文件和账号的关系
            String filepath = "userFile/"+account+"/"+newfileName;
                   loginService.updateAdmin(id,filepath);
​
            commonResult = new CommonResult(200, filepath, "查询成功");
        } catch (Exception e) {
            e.printStackTrace();
            commonResult = new CommonResult(500, null, "查询成功");
        }
        return commonResult;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值