SpringMVC

SpringMVC

1、概述

1.1、什么是MVC

MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。

  • 是将业务逻辑、数据、显示分离的方法来组织代码。
  • MVC主要作用是降低了视图与业务逻辑间的双向偶合。
  • MVC不是一种设计模式,是一种架构模式。 当然不同的MVC存在差异。

Model(模型):数据模型,提供要展示的数据,包括数据和业务。
View(视图):负责进行模型的展示,用户界面。
Controller(控制器):控制器做调度员的工作,处理用户请求,将数据返回给视图进行展示。

最典型的MVC就是JSP + servlet + javabean的模式。
什么是SpringMVC

1.2、什么是SpringMVC

基于Java实现MVC的轻量级Web框架(底层是Servlet)。

Spring MVC的特点

  • 轻量级,简单易学
  • 高效 , 基于请求响应的MVC框架
  • 与Spring兼容性好,无缝结合
  • 约定优于配置
  • 功能强大:RESTful、数据验证、格式化、本地化、主题等
  • 简洁灵活
  • 最重要的一点还是用的人多,使用的公司多 。

SpringMVC围绕DispatcherServlet [ 调度Servlet ] 设计。

DispatcherServlet的作用是将请求分发到不同的处理器。
在这里插入图片描述

2、SpringMVC处理流程

在这里插入图片描述

  • 主要分为三步:
    • 处理映射器,找到对应的Handler
    • 处理适配器:对Handler封装,找到对应的Controller类
    • 视图解析器:解析视图
  1. 用户的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。
  2. DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping处理器映射的配置找到处理该请求的Handler
  3. 在这个地方Spring会通过HandlerAdapter对该处理器进行封装。
  4. HandlerAdapter处理器适配器,适配到对应的Controller层,Java类。
  5. Controller执行对应的业务方法,返回对应的ModelAndView对象给DispatcherServlet,ModelAndView包含了数据和视图信息。
  6. ModelAndView是逻辑视图,DispatcherServlet还要通过ViewResolver视图解析器完成从逻辑视图到真实视图对象的解析工作。
  7. 当得到真正的视图对象后,DispatcherServlet通过视图对象对模型数据进行渲染,返回给用户。
  8. 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。

3、第一个SpringMVC程序

导入依赖

<!--SpringMVC依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.1</version>
</dependency>
<!--将复杂对象转化成Json格式,只需要导入这个依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.2</version>
</dependency>

配置web.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!--1.注册servlet-->
    <servlet>
        <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:springmvc-servlet.xml</param-value>
        </init-param>
        <!-- 启动顺序,数字越小,启动越早 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--所有请求都会被springmvc拦截
    / :匹配所有的请求;(不包括.jsp)
    /* :匹配所有的请求;(包括.jsp)
    -->
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
	<!--字符编码有问题,配置过滤器-->
    <filter>
        <filter-name>encoding</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>encoding</filter-name>
        <url-pattern>/</url-pattern>
    </filter-mapping>
</web-app>

配置springmvc-servlet.xml

<?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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
    <context:component-scan base-package="com.lvboaa.controller"/>
    <!-- 过滤静态资源,不需要走视图解析器,可直接访问静态资源 -->
    <mvc:default-servlet-handler />
    <!--支持mvc注解驱动,完成处理映射器和处理适配器的自动装配-->
    <!--<mvc:annotation-driven />-->
	<!--处理乱码-->
    <mvc:annotation-driven >
        <mvc:message-converters register-defaults="true">
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <constructor-arg value="UTF-8"/>
            </bean>
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
                <property name="objectMapper">
                    <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                        <property name="failOnEmptyBeans" value="false"/>
                    </bean>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          id="internalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/" />
        <!-- 后缀 -->
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

编写Controller类

//@RestController将返回的对象转成JSON格式,不走视图解析器
@RestController
@RequestMapping("/")
public class HelloController {
    @RequestMapping("/hello")
    public String hello(){
        return "hello";
    }
}

可能遇到的问题:访问路径出现404错误

  • 查看编译目录是否缺少lib文件夹(没有对于的依赖)
  • 在项目结构的Artifacts添加lib目录导入依赖
  • 重启Tomcat

4、Controller和RestFul

4.1、Controller实现

实现Controller接口

  • 不推荐使用,一个请求就需要实现一个类

注解实现@Controller

  • 更简洁地实现servlet
  • 如果需要使用视图,多个请求都可以指向一个视图,但是页面结果可以不一样,视图可被复用,控制器与视图之间是弱偶合关系。

4.2、RestFul风格

Restful就是一个资源定位及资源操作的风格。不是标准也不是协议。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

功能

  • 通过不同的请求方法实现不同的效果,请求路径url可以一样,实现的功能不同
http://127.0.0.1/item/1 查询,GET
http://127.0.0.1/item 新增,POST
http://127.0.0.1/item 更新,PUT
http://127.0.0.1/item/1 删除,DELETE

注意

  • @RestController=@ResponseBody(返回字符串)+@Controller
  • 将删除的id这些参数放到url,@PathVariable表示url地址栏的参数
  • 传入对象的话直接在形参方写成一个对象
  • @RequestParam表示必须传的参数,用在形参

实现

//RequestMapping默认get和post方法都可访问
//@RequestMapping(path = "/add/{a}/{b}",method = RequestMethod.POST)
@PostMapping("/{a}/{b}")
public String add1(@PathVariable int a,@PathVariable int b){
    String str = "实现添加业务";
    return "add";
}
//等于RequestMapping的method为get
@GetMapping("/{a}")
public String add3(@PathVariable int a){
   String str = "执行查询业务";
    return "add";
}

注意:网页状态码错误

  • 100+:服务器收到请求,需要请求者执行操作
  • 200+:成功
  • 300+:客户端请求重定向
  • 400+:客户端请求错误(找不到文件)
  • 500+:服务器代码错误

转发和重定向的区别

  • 转发是服务器收到请求后为了完成响应跳转到一个新的地址,请求一次;重定向是完成响应后需要请求新的地址,至少请求两次
  • 转发url不会变化,重定向会发生变化
  • 重定向不会共享数据,转发共享
  • 重定向可跳转至任意页面,转发只能本站页面
  • 转发是服务器端行为,重定向是客户端行为

4.3、使用JSON交互前后端

导入依赖

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

实现

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/t1")
    public String add(@RequestParam("username") String name){
        System.out.println(name);
        return name;
    }
    @GetMapping("/t2")
    public User add2(User user){
        System.out.println(user);
        return user;
    }
}

解决JSON中文编码问题(springmvc-servlet.xml)

<mvc:annotation-driven>
   <mvc:message-converters register-defaults="true">
       <bean class="org.springframework.http.converter.StringHttpMessageConverter">
           <constructor-arg value="UTF-8"/>
       </bean>
       <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
           <property name="objectMapper">
               <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                   <property name="failOnEmptyBeans" value="false"/>
               </bean>
           </property>
       </bean>
   </mvc:message-converters>
</mvc:annotation-driven>

5、AJAX异步请求

实现页面的异步局部更新。

导入jquery-3.5.1.js

  • 异步请求代码

<script src="/js/jquery-3.5.1.js"></script>
<script>
    function a1() {
        //还有get和ajax方法
        $.post({
           url: "/a3",
           data: {
               name: $('#name').val()
           },
           success: function (data) {
               console.log(data);
           }
        });
    }
</script>

6、拦截器

6.1、简介

拦截器类似于过滤器

过滤器与拦截器的区别:拦截器是AOP思想的具体应用。

不改变源码拦截请求

  • 过滤器
    • servlet规范中的一部分,任何java web工程都可以使用
    • 在url-pattern中配置了/*之后,可以对所有要访问的资源进行过滤(包括jsp页面,/不包括)
  • 拦截器
    • 拦截器是SpringMVC框架自己的,只有使用SpringMVC才能使用
    • 拦截器只会拦截访问的控制器请求,默认静态资源过滤,访问静态资源不会拦截

6.2、拦截器实现

实现接口

public class MyInterceptor implements HandlerInterceptor {

    //在请求处理的方法之前执行
    //如果返回true执行下一个拦截器,放行
    //如果返回false就不执行下一个拦截器,阻塞在这
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("=========处理前=========");
        return true;
    }

    //postHandle和afterCompletion相当于是日志拦截
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("=========处理后=========");
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("=========清理=========");
    }
}

配置springmvc.xml文件

<mvc:interceptors>
    <mvc:interceptor>
        <!--/**表示过滤/下面的所有请求-->
        <mvc:mapping path="/**"/>
        <bean class="com.lvboaa.config.MyInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

实现用户登录拦截器

  • 原理:根据cookie判断是否登录
  • 控制器
@Controller
@RequestMapping("/user")
public class UserController {
    //跳转到登陆页面
    @RequestMapping("/tologin")
    public String toLogin() throws Exception {
        return "login";
    }

    //跳转到成功页面
    @RequestMapping("/toSuccess")
    public String jumpSuccess() throws Exception {
        return "success";
    }

    //登陆提交
    @RequestMapping("/login")
    public String login(HttpSession session, String username, String pwd) throws Exception {
        // 向session记录用户身份信息
        System.out.println("接收前端==="+username);
        session.setAttribute("user", username);
        return "success";
    }

    //退出登陆
    @RequestMapping("logout")
    public String logout(HttpSession session) throws Exception {
        //session 过期
        session.invalidate();
        return "login";
    }
}
  • 拦截器类
public class UserInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("uri: " + request.getRequestURI());
        //请求包含login字符串直接放行
        if (request.getRequestURI().contains("login")) {
            return true;
        }
        HttpSession session = request.getSession();

        // 如果用户已登陆也放行
        if(session.getAttribute("user") != null) {
            return true;
        }

        // 用户没有登陆跳转到登陆页面
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        return false;
    }
}
  • 配置拦截器
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/user/**"/>
        <bean class="com.lvboaa.config.UserInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

7、文件上传下载

导入依赖

<!--文件上传-->
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>javax.servlet-api</artifactId>
   <version>4.0.1</version>
</dependency>

配置springmvc.xml配置文件

<!--文件上传配置-->
<bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
   <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
   <property name="defaultEncoding" value="utf-8"/>
   <!-- 上传文件大小上限,单位为字节(10485760=10M) -->
   <property name="maxUploadSize" value="10485760"/>
   <property name="maxInMemorySize" value="40960"/>
</bean>

控制器实现上传下载代码

@RestController
public class FileController {
    @RequestMapping("/upload")
    //方式一
    public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {

        //获取文件名 : file.getOriginalFilename();
        String uploadFileName = file.getOriginalFilename();

        //如果文件名为空,直接回到首页!
        if ("".equals(uploadFileName)){
            return "redirect:/index.jsp";
        }
        System.out.println("上传文件名 : "+uploadFileName);

        //上传路径保存设置,
        String path = request.getServletContext().getRealPath("/upload");
        //如果路径不存在,创建一个
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
        System.out.println("上传文件保存地址:"+realPath);

        InputStream is = file.getInputStream(); //文件输入流
        OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //文件输出流

        //读取写出
        int len=0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer,0,len);
            os.flush();
        }
        os.close();
        is.close();
        return "redirect:/index.jsp";
    }

    @RequestMapping("/upload2")
    //方式2
    public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {

        //上传路径保存设置
        String path = request.getServletContext().getRealPath("/upload");
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
        //上传文件地址
        System.out.println("上传文件保存地址:"+realPath);

        //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
        file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));

        return "上传成功";
    }
    @RequestMapping("/download")
    public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
        //要下载的图片地址
        String  path = request.getServletContext().getRealPath("/upload");
        String  fileName = "需求文档.txt";

        //1、设置response 响应头
        response.reset(); //设置页面不缓存,清空buffer
        response.setCharacterEncoding("UTF-8"); //字符编码
        response.setContentType("multipart/form-data"); //二进制传输数据
        //设置响应头
        response.setHeader("Content-Disposition",
                "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));

        File file = new File(path,fileName);
        //2、 读取文件--输入流
        InputStream input=new FileInputStream(file);
        //3、 写出文件--输出流
        OutputStream out = response.getOutputStream();

        byte[] buff =new byte[1024];
        int index=0;
        //4、执行 写出操作
        while((index= input.read(buff))!= -1){
            out.write(buff, 0, index);
            out.flush();
        }
        out.close();
        input.close();
        return "success";
    }
}

前端使用表单文件上传组件

  • 也可以使用链接a标签实现下载文件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值