SpringMVC

9 篇文章 0 订阅
2 篇文章 0 订阅

一、SpringMVC概述

Spring MVC是由Spring官方提供的基于MVC设计理念的web框架。

Spring MVC是基于Servlet封装的用于实现MVC控制的框架,实现前端、服务端的交互。

1.1 SpringMVC优势

  • 严格遵守了分层思想;
  • 采用了松耦合、插件式结构,相比较于自己封装的BaseServlet以及其他的一些MVC框架,更加灵活、更具扩展性;
  • SpringMVC是基于Spring的扩展,提供了一套完善的MVC注解;
  • SpringMVC在数据绑定、视图解析都提供了多种处理方式,可灵活配置;
  • SpringMVC对RESTFUL URL设计风格提供了良好的支持。

1.2 SpringMVC工作原理

  • 接受并解析请求;
  • 处理请求;
  • 数据渲染、响应请求;

二、SpringMVC框架部署

2.1 基于Maven创建一个web工程

2.2 添加SpringMVC依赖

  • spring-context
  • aspects
  • jdbc
  • web
  • webmvc
  • junit
    <properties>
        <spring.version>5.3.2</spring.version> <!--统一定义版本-->
        <maven.compiler.source>15</maven.compiler.source>
        <maven.compiler.target>15</maven.compiler.target>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

 2.3 创建SpringMVC配置文件

  • 在resource目录下创建名为spring-servlet.xml的文件
  • 添加MVC命名空间
<?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:aop="http://www.springframework.org/schema/aop"
       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
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/mvc 
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:annotation-config/>
    <context:component-scan base-package="com.xsbc"/>
    
    <!-- 声明MVC使用注解驱动 -->
    <mvc:annotation-driven />
</beans>

2.4 在web.xml中配置SpringMVC的前端控制器

SpringMVC提供了一个名为DispatcherServlet的类(SpringMVC中央处理器-前端控制器),用于拦截用户请求交由SpringMVC处理

<?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">
    
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
</web-app>

三、SpringMVC框架使用

在SpringMVC中,将接受用户请求、处理用户请求的类称为Controller(控制器)

3.1 创建控制器

1)创建控制器类

  • 创建一个名为‘com.xsbc.controllers’的包(此包需在Spring注解扫描的范围内);
  • 创建一个类(无需做任何继承和实现);
  • 在类上添加‘@Controller’注解,声明此类为SpringMVC的控制器;
  • 在类上添加‘@RequestMapping("url")’,声明此控制器类的请求url;
@Controller
@RequestMapping("/book")
public class BookController {
    
}

2) 在控制器类中定义处理请求的方法

  • 在一个控制器类中可以定义多个方法处理不同请求;
  • 在每个方法上添加@requestMapping("url")用于声明当前方法的请求url;
@Controller
@RequestMapping("/book")
public class BookController {
    @RequestMapping("/add")
    public void addBook(){
        System.out.println("----book  add-----");
    }
    @RequestMapping("/list")
    public void listBooks(){
        System.out.println("----book  list-----");
    }
}

3) 访问

http://localhost:8080/springmvc_demo1/book/addhttp://localhost:8080/springmvc_demo1/book/add

3.2 静态资源配置

静态资源:项目中的HTML、css、js、图片、字体等

1)/*和/的区别

  • /*表示拦截所有的HTTP请求,包括静态资源请求(html、css、js、图片),包括.jsp请求,都做为控制器类的请求路径来处理;
  • /表示拦截所有的HTTP请求,包括静态资源请求(html、css、js、图片),但不包括.jsp请求,都做为控制器类的请求路径来处理;

2)静态资源的放行配置

  • 在SpringMVC的配置文件,添加如下静态资源执行的配置
    <mvc:resources mapping="/css/**" location="/css/" />
    <mvc:resources mapping="/js/**" location="/js/" />
    <mvc:resources mapping="/img/**" location="/img/" />
    <mvc:resources mapping="/page/**" location="/page/" />

3.3 前端提交数据到控制器

  • book-add.jsp 表单的action属性设置控制器类的url和对应方法的url组合路径
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h3>添加图片</h3>
    <form action="book/add" method="post">
        <p>图书名称:<input type="text"/></p>
        <p>图书作者:<input type="text"/></p>
        <p>图书价格:<input type="text"/></p>
        <p><input type="submit" value="提交"/></p>
    </form>
</body>
</html>

1)表单提交

  • 表单提交:输入框需要提供name属性,SpringMVC控制器是通过name属性值的;
<html>
<head>
    <title>Title</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <h3>添加图片</h3>
    <form action="book/add" method="post">
        <p>图书名称:<input type="text"/></p>
        <p>图书作者:<input type="text"/></p>
        <p>图书价格:<input type="text"/></p>
        <p><input type="submit" value="提交"/></p>
    </form>
</body>
</html>

 2)URL提交

  • 超链接(URL)提交:<a href="book/add?bookName=Java">URL提交</a>;

 3)AJAX提交

  • AJAX提交:请求行、请求头、请求体都可以用来传值;
 <H3>AJAX提交</H3>
    <input type="button" value="ajax提交" id="btn1"/>
    <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
    <script type="text/javascript">
        $("#btn1").click(function(){
            var obj={};
            obj.bookName="Java";
            obj.bookAutor="张三";
            obj.bookPrice=3.33;
            
            $.ajax({
                url:"book/add",
                type:"post",
                headers:{
                    
                },
                contentType:"application/json",
                data:obj,
                success:function(res){
                    console.log(res);
                }
            })
        });
    </script>

3.4 控制器接受前端提交的数据

1)请求行传值

  • 表单提交
  • URL提交
  • $.ajax请求的url传值
  • $.post( )/$.get( )中的{ }传值

@RequestParam注解用于接受请求行传递的数据

  • 前端接收数据
    <h3>表单提交</h3>
    <form action="book/add" method="post">
        <p>图书名称:<input type="text" name="name"/></p>
        <p>图书作者:<input type="text" name="author"/></p>
        <p>图书价格:<input type="text" name="price"/></p>
        <p><input type="submit" value="提交"/></p>
    </form>
  • 控制器接受数据 
@Controller
@RequestMapping("/book")
public class BookController {
    // 接受请求行传输的数据
    @RequestMapping("/add")
    public void addBook(@RequestParam(value="name") String name,
                        @RequestParam(value="author")String author,
                        @RequestParam(value="price")double price){
        System.out.println(name+"\n"+author+"\n"+price);
    }
}

注意:

如果控制器方法中接收的参数名与请求行传值的key一致,则@RequestParam注解可省略 

@Controller
@RequestMapping("/book")
public class BookController {
    // 接受请求行传输的数据
    @RequestMapping("/add")
    public void addBook(String name,
                        String author,
                        double price){
        System.out.println(name+"\n"+author+"\n"+price);
    }
}

 2)请求头传值

$.ajax({
    ....
    headers:{

    },
    ....
})

 @RequestHeader注解用于接受请求头传递的数据

  • 前端
    <h3>AJAX提交</h3>
    <input type="button" value="ajax提交" id="btn1"/>
    <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
    <script type="text/javascript">
        $("#btn1").click(function(){
            var obj={};
            obj.bookName="Java";
            obj.bookAutor="张三";
            obj.bookPrice=3.33;

            $.ajax({
                url:"book/list",
                type:"post",
                headers:{
                    token: "Hello, world"
                },
                success:function(res){
                    console.log(res);
                }
            });
        });
    </script>
  • 控制器
    @RequestMapping("/list")
    public void listBooks(@RequestHeader("token") String token){
        System.out.println(token);
        System.out.println("----book  list-----");
    }

 3)请求体传值

  • ajax封装请求体数据
$.ajax({
    ....
    data:{

    },
    ....
})

@RequestBody 注解用于接受请求行头传递的数据

  • 前端
  <input type="button" value="ajax提交" id="btn1"/>
    <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
    <script type="text/javascript">
        $("#btn1").click(function(){
            var obj={};
            obj.bookName="Java";
            obj.bookAuthor="张三";
            obj.bookPrice=2.33;
            
            var s=JSON.stringify(obj);
            $.ajax({
                url:"book/update",
                type:"post",
                contentType:"application/json",
                data:s,
                success:function(res){
                    console.log(res);
                }
            });
        });
    </script>

注意:data的值为json格式字符串 ,因此contentType必须设置为"application/json"

  • 后端 

@RequestBody 将前端请求体提交的JSON格式数据转换成Java对象,依赖jackson包

  • 导入jackson依赖
        <!-- json依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.1</version>
        </dependency>
  • 控制器
    @RequestMapping("/update")
    public void update(@RequestBody Book book){
        System.out.println("----book  update----");
        /*
        try {
            //Servlet的处理方式使用request的输入流接受请求体数据
            ServletInputStream is=request.getInputStream();
            StringBuffer res=new StringBuffer();
            byte[] buf=new byte[100];
            int len=-1;
            while((len=is.read(buf))!=-1){
                String s=new String(buf,0,len);
                res.append(s);
            }
            System.out.println(res.toString());
        }catch(IOException e){
            e.printStackTrace();
        }
        */
        System.out.println(book);
    }

 3.5 控制器响应前端请求

1)控制器响应同步请求

同步请求:form、超链接

  • 处理同步请求的方法返回类型定义为String或ModelAndView,以实现页面的跳转
  • 返回类型为String

请求跳转(转发) 

    @RequestMapping("/add")
    public String addBook(@RequestParam("name") String name,
                                @RequestParam("author")String author,
                                @RequestParam("price")double price){
        System.out.println(name+"\n"+author+"\n"+price);
        return "/tips.jsp";
    }

重定向 

    @RequestMapping("/add")
    public String addBook(@RequestParam("name") String name,
                                @RequestParam("author")String author,
                                @RequestParam("price")double price){
        System.out.println(name+"\n"+author+"\n"+price);
        return "redirect:/tips.jsp";
    }
  • 返回类型是ModelAndView

请求跳转(转发)  

    @RequestMapping("/add")
    public ModelAndView addBook(@RequestParam("name") String name,
                                @RequestParam("author")String author,
                                @RequestParam("price")double price){
        System.out.println(name+" "+author+" "+price);
        return new ModelAndView("/tips.jsp");
    }

重定向 

    @RequestMapping("/add")
    public ModelAndView addBook(@RequestParam("name") String name,
                                @RequestParam("author")String author,
                                @RequestParam("price")double price){
        System.out.println(name+" "+author+" "+price);
        return new ModelAndView("redirect:/tips.jsp");
    }

2)控制器响应异步请求

异步请求:ajax请求

  • 使用response中的输出流进行响应
  • 控制器方法的返回类型为void
  • 控制器方法添加'HttpServletResponse response'参数
  • 在方法中通过response获取输出流,使用流响应AJAX请求
    @RequestMapping("/update")
    public void update(@RequestBody Book book, HttpServletResponse response) 
        throws IOException {
        System.out.println("----book  update----");
        System.out.println(book);

        //使用ObjectMapper将对象转换为JSON格式字符串
        String s=new ObjectMapper().writeValueAsString(book);
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json");
        PrintWriter out=response.getWriter();
        out.println(s);
        out.flush();
        out.close();
    }
  • 直接在控制器方法返回响应的对象
  • 控制器方法的返回类型设置为响应给ajax请求的对象类型
  • 在控制器方法前添加@ResponseBody注解,将返回的对象转换为JSON响应给ajax请求
  • 如果一个控制器类中的所有方法都是响应ajax请求,则可以直接在控制器类前添加
    @RequestMapping("/update")
    @ResponseBody
    public List<Book> update(@RequestBody Book book){
        System.out.println("----book  update----");
        System.out.println(book);

        List<Book> books=new ArrayList<>();
        books.add(new Book(1,"Java","老王",2.44));
        books.add(new Book(2,"C++","王阿姨",4.25));
        return books;
    }

3)控制器响应同步请求的数据传递

对于同步请求的转发响应,可以传递参数到转发的页面

  • 返回类型为String
  1. 在控制器方法中定义一个Model类型的参数
  2. 在return页面之前,向model中添加键值对,添加的键值对就会被传递到转发的页面
    @RequestMapping("/add")
    public String addBook(String name, String author, double price,
         Model model){
        System.out.println(name+" "+author+" "+price);
        model.addAttribute("key1","key2");
        model.addAttribute("book",new Book(1,"Java","老王",2.44));
        return "/tips.jsp";
    }

注意:

除了使用Model对象传值以外,还可以直接使用HttpServletRequest对象

    @RequestMapping("/add")
    public String addBook(String name, String author, double price,
         HttpServletRequest request){
        System.out.println(name+" "+author+" "+price);
        request.addAttribute("key1","key2");
        request.addAttribute("book",new Book(1,"Java","老王",2.44));
        return "/tips.jsp";
    }
  • 返回类型为ModelAndView
    @RequestMapping("/add2")
    public ModelAndView addBook2(String name, String author, double price){
        System.out.println(name+" "+author+" "+price);
        ModelAndView modelAndView=new ModelAndView("/tips.jsp");
        modelAndView.addObject("key1","value2");
        modelAndView.addObject("book",new Book(1,"C++","老王",2.44));
        return modelAndView;
    }

3.6 解决中文乱码问题

1)前端编码

  • JSP页面
<%@ page contentType="text/html;charset=UTF-8" 
language="java" pageEncoding="UTF-8" %>
  • HTML页面
<meta charset="UTF-8">

2)服务器编码

  • tomcat/conf/server.xml
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="UTF-8"/>

3)设置SpringMVC的编码方式

  • 在web.xml中配置SpringMVC编码过滤器的编码方式
   <!-- 设置编码格式,解决乱码问题 -->
    <filter>
        <filter-name>EncodingFilter</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>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

四、SpringMVC的请求处理流程

4.1 请求处理过程

SpringMVC通过前端控制器(DispatcherServlet)拦截并处理用户请求的

  1.  前端发送请求被前端控制器DispatcherServlet拦截;
  2. 前端控制器调用处理器映射器HandlerMapping对请求URL进行解析,解析之后返回调用给前端控制器;
  3. 前端控制器调用处理器适配器处理调用链;
  4. 处理器适配器基于反射通过适配器设计模式完成处理器(控制器)的调用处理用户请求;
  5. 处理器适配器将控制器返回的视图和数据信息封装成ModelAndView响应给前端控制器;
  6. 前端控制器调用视图解析器ViewResolver对ModelAndView进行解析,将解析结果(视图资源和数据)响应给前端控制器;
  7. 前端控制器调用视图view组件将数据进行渲染,将渲染结果(静态视图)响应给前端控制器;
  8. 前端控制器响应用户请求;

4.2 SpringMVC的核心组件

  • DispacherServlet前端控制器、总控制器
  • 由SpringMVC提交,无需新一代农民工(码农)开发;
  • 作用:接收请求,协同各个组件工作、响应请求;
  • HanlderMapping处理器映射
  • 由SpringMVC提交,无需新一代农民工(码农)开发;
  • 作用:负责根据用户请求的URL找到对应的Handler;
  • 可配置:SpringMVC提供多个处理器映射的实现,可以根据需要进行配置;
  • HanlderAdapter处理器适配器
  • 由SpringMVC提交,无需新一代农名工(码农)开发;
  • 作用:按照处理器映射器解析的用户请求的调用链,通过适配器模式完成Hanlder的调用;
  • Handler处理器
  • 由农民工根据业务的的需求进行开发;
  • 作用:处理请求;
  • ModelAndView视图模型
  • 作用:用于封装处理器返回的数据以及相应的视图;
  • ModelAndView=Model+view;
  • ViewResolver视图解析器
  • 作用:对ModelAndView进行解析;
  • 可配置:SpringMVC提供多个处理器映射的实现,可以根据需要进行配置;
  • View视图
  • 作用:完成数据渲染;

4.3 处理器映射

不同的处理器映射对URL处理的方式也不相同,使用对应的处理器映射之后前端的请求规则也需要发生相应的变化。

  • BeanNameUrlHandlerMapping 根据控制器ID访问控制器
  • SimpleUrlHandlerMapping 根据控制器配置的URL访问(默认)

配置处理器映射器:

  • 在SpringMVC的配置文件中通过bean标签声明处理器映射器
  • 配置BeanNameUrlHandlerMapping
<bean class="
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
  • 配置 SimpleUrlHandlerMapping(默认情况下,无需配置)
    <bean class=
   "org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/aaa">bookController</prop>
                <prop key="/bbb">studentController</prop>
            </props>
        </property>
    </bean>

4.4 视图解析器

Spring提供了多个视图解析器:

  • UrlBasedViewResolver
  • InternalResourceViewResolver

1)UrlBasedViewResolver

  • 需添加JSTL的依赖
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
  • 配置视图解析器
    <bean id="viewResolver" class="
        org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass" 
        value="org.springframework.web.servlet.view.JstlView" />
        <property name="prefix" value="/" />
        <property name="suffix" value=".jsp" />
    </bean>

2)InternalResourceViewResolver

    <bean id="viewResolver" class=" 
        org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/" />
        <property name="suffix" value=".jsp" />
    </bean>

五、日期格式处理

5.1 在控制器中使用对象接收数据

  • 前端
    <form action="test/add" method="post">
        <p>图书名称:<input type="text" name="bookName"/></p>
        <p>图书作者:<input type="text" name="bookAuthor"/></p>
        <p>图书价格:<input type="text" name="bookPrice"/></p>
        <p><input type="submit" value="提交"/></p>
    </form>
  • 后端
@Controller
@RequestMapping("/test")
public class TestController {

    @RequestMapping("/add")
    //表单提交的多个数据,在控制器方法中可以使用对象进行接收
    //但是提交的数据key必须要与对象的属性名一致
    public String addBook(Book book){
        System.out.println(book);
        return "/tips.jsp";
    }
}

5.2 日期格式处理

如果前端需输入日期数据,在控制器中转换成Date对象,SpringMVC要求前端输入的日期格式必须为:yyyy/MM/dd

如果甲方要求日期格式必须为指定的格式,而这个指定格式SpringMVC不接受,该如何处理?

  • 自定义日期格式

1)创建自定义日期转换器

  • 创建一个类实现Converter接口,泛型指定从什么类型转换为什么类型
  • 实现convert转换方法

public class MyDateConverter implements Converter<String,Date> {
    
    SimpleDateFormat sdf=new SimpleDateFormat("yyyy年MM月dd日");
    
    public Date convert(String s) {
        Date date=null;
        try {
            date=sdf.parse(s);
        }catch(ParseException e){
            e.printStackTrace();
        }
        return date
    }

}

2)配置自定义转换器

<!-- 声明MVC使用注解驱动 -->
<mvc:annotation-driven conversion-service="converterFactory"/>
<bean id="converterFactory" class=
"org.springframework.format.support.FormattingConversionServiceFactoryBean">
   <property name="converters">
       <set>
          <bean class="com.xsbc.utils.MyDateConverter" />
       </set>
   </property>
</bean>

六、文件上传

6.1 SpringMVC框架部署

  • 基于Maven创建web工程
  • 添加SpringMVC所需的依赖
  • Spring:context、aspects、jdbc、test、webmvc、jackson
  • 创建SpringMVC配置文件
  • 在web.xml中配置SpringMVC的前端控制器
  • 在web.xml中配置SpringMVC的编码过滤器
  • 配置springmvc静态资源处理策略

6.2 文件上传

案例:添加图书,同时提交图书的封面图片

 1)前端提交文件

  • 表单提交方式必须为post
  • 表单enctype属性设置为mutilpart/form-data
    <h4>添加图书信息</h4>
    <form action="book/add" method="post" enctype="multipart/form-data">
        <p>图书名称:<input type="text" name="bookName" /></p>
        <p>图书作者:<input type="text" name="bookAuthor" /></p>
        <p>图书价格:<input type="text" name="bookPrice" /></p>
        <p>图书封面:<input type="file" name="imgFile" /></p>
        <p><input type="submit" value="提交" /></p>
    </form>

2)控制器接收数据和文件

SpringMVC处理上传文件需借助于CommonsMultipartResolver文件解析器

  • 添加依赖:commons-io、commons-fileupload
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
  • 在spring-servlet.xml中配置文件解析器
    <bean id="multipartResolver" class="org.springframework.web.multipart.
        commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10240000" />
        <property name="maxInMemorySize" value="102400" />
        <property name="defaultEncoding" value="utf-8" />
    </bean>
  • 控制器接收文件
  • 在处理文件上传的方法中定义一个MultipartFile类型的对象,就可以接收图片
@Controller
@RequestMapping("/book")
public class BookController {

    @RequestMapping("/add")
    public String addBook(Book book, MultipartFile imgFile,
            HttpServletRequest request) throws IOException {
        System.out.println("------------add");
        //imgFile表示上传的图片
        // 1、截取上传文件的后缀名,生成新的文件名
        String originalFilename=imgFile.getOriginalFilename();
        assert originalFilename != null;
        String ext=originalFilename.substring(
            originalFilename.lastIndexOf("."));//.jpg
        String fileName=System.currentTimeMillis()+ ext;

        //2、获取img目录在服务器的路径
        String dir=request.getServletContext().getRealPath("img");
        String savePath=dir+"/"+fileName;//两个斜杆\\代表\
        //3、保存文件
        imgFile.transferTo(new File(savePath));

        //4、将图片的访问路径设置为book对象
        book.setBookImg("img/"+fileName);

        //5、调用service保存book到数据库
       return "/tips.jsp";
    }
}

6.3 文件下载

1)文件下载流程

  • list.jsp 
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
      integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu"
      crossorigin="anonymous">

    <!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css"
      integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ"
      crossorigin="anonymous">

<body>
    <h4>文件列表</h4>
    <div class="row" id="container">

    </div>
    <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"
            integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
            crossorigin="anonymous">
    </script>
    <script type="text/javascript">
        $.get("book/list",function(res){
            for(var i=0;i<res.length;i++){
                var fn=res[i];
                var htmlStr="<div class='col-lg-2 col-md-3 col-sm-4 col-xs-6'><div class='thumbnail'><img src='img/"+fn+"' alt='...'> <div class='caption'> <p><a href='#' class='btn btn-primary' role='button'>下载</a></p> </div> </div> </div>";
                $("#container").append(htmlStr);
            }
        },"json");
    </script>
</body>
</html>
  • BookController
    @RequestMapping("/list")
    @ResponseBody
    public String[] listImg(HttpServletRequest request){
        //1、从img目录下获取所有的图片信息
        String dir=request.getServletContext().getRealPath("img");
        File imgDir=new File(dir);
        String[] fileNames=imgDir.list();
        return fileNames;
    }

2)实现文件下载

  • list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
      integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu"
      crossorigin="anonymous">

    <!-- 可选的 Bootstrap 主题文件(一般不用引入) -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap-theme.min.css"
      integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ"
      crossorigin="anonymous">

<body>
    <h4>文件列表</h4>
    <div class="row" id="container">

    </div>
    <script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"
            integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd"
            crossorigin="anonymous">
    </script>
    <script type="text/javascript">
        $.get("book/list",function(res){
            for(var i=0;i<res.length;i++){
                var fn=res[i];
                var htmlStr="<div class='col-lg-2 col-md-3 col-sm-4 col-xs-6'><div class='thumbnail'><img src='img/"+fn+"' alt='...'> <div class='caption'> <p><a href='book/download?fname="+fn+"' class='btn btn-primary' role='button'>下载</a></p> </div> </div> </div>";
                $("#container").append(htmlStr);
            }
        },"json");
    </script>
</body>
</html>
  • BookController

@RequestMapping("/download")
public void downloadImg(String fname, HttpServletRequest request, 
     HttpServletResponse response) throws Exception {
     //从img目录找到当前文件
     String dir=request.getServletContext().getRealPath("img");
     String filePath=dir+"/"+fname;

     FileInputStream fileInputStream = new FileInputStream(filePath);
     //设置浏览器不能识别,让其自动下载而不是在浏览器中显示
     response.setContentType("application/exe");
     // 避免浏览器自动打开文件
     response.addHeader("Content-Disposition","attachment;filename="+fname);
     IOUtils.copy(fileInputStream,response.getOutputStream());
}

七、统一异常处理

在应用系统运行过程中,可能由于运行环境、用户操作、资源不足等各个方面的原因导致系统出现异常(HTTP状态异常、Exception);如果系统出现异常,这些异常将会通过浏览器呈现给用户,而这些异常的显示是没有必要的,因此可以在服务器进行特定的处理,即当系统出现异常之后,呈现给用户一个统一的、可读的异常显示页面。

7.1 HTTP异常状态统一处理

HTTP Status 404

  • 创建一个用于进行异常提示的页面:404.jsp
  • 在web.xml文件中进行配置
    <error-page>
        <error-code>404</error-code>
        <location>/404.jsp</location>
    </error-page>

7.2 Java代码异常的统一处理

1)基于Servlet-api的处理

  • 创建异常提示页面:err.jsp
  • 在web.xml中进行配置
    <error-page>
        <exception-type>java.lang.NumberFormatException</exception-type>
        <location>/err.jsp</location>
    </error-page>

2)SpringMVC处理

  • 定义一个异常处理类
@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(NullPointerException.class)
    public String nullHandler(){
        return "/err1.jsp";
    }

    @ExceptionHandler(NumberFormatException.class)
    public String formatHandler(){
        return "/err2.jsp";
    }
}

八、拦截器

8.1 拦截器介绍

SpringMVC提供的拦截器就类似于Servlet-api中的过滤器,可以对控制器的请求进行拦截实现相关的预处理和后处理

  • 过滤器
  • 是Servlet规范的一部分,所有的web项目都可以使用;
  • 过滤器在web.xml中配置(可以使用注解),能够拦截所有的web请求;
  • 拦截器
  • 是SpringMVC框架的实现,只有在SpringMVC框架中使用;
  • 拦截器在SpringMVC配置文件进行配置,不会拦截SpringMVC放行的资源(jsp\html\css);

8.2 自定义拦截器

1)创建拦截器

public class MyInterceptor1 implements HandlerInterceptor {

    @Override
    //预处理方法
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
           Object handler) throws Exception {
        System.out.println("---------预处理-------");
        Enumeration<String> keys=request.getParameterNames();
        while(keys.hasMoreElements()){
            String key=keys.nextElement();
            if("bookId".equals(key)){
                return true;
            }
        }
        response.setStatus(400);
        //当拦截器的preHandle返回false后的处理
        //后续的拦截器以及请求处理方法等都不会再执行
        return false;
    }

    @Override
    //后处理方法
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
           Object handler, ModelAndView modelAndView) throws Exception {
        modelAndView.addObject("tips","这是通过拦截器后处理添加的数据");
        System.out.println("---------后处理--------");
    }
}

 2)配置拦截器

   <!-- 
        拦截器的配置 
            mapping表示拦截所有的/student/**
            exclude-mapping表示拦截/student下的除了/add外
    -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/book/query" />
            <mvc:mapping path="/book/add" />
            <mvc:mapping path="/student/**" />
            <mvc:exclude-mapping path="/student/add" /> 
            <bean class="com.xsbc.utils.MyInterceptor1" />
        </mvc:interceptor>
    </mvc:interceptors>

8.3 拦截器链

将多个拦截器按照一定的顺序构成一个执行链,执行顺序按照配置文件中的声明顺序。

    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/book/query" />
            <mvc:mapping path="/book/add" />
            <mvc:mapping path="/student/**" />
            <mvc:exclude-mapping path="/student/add" />
            <bean class="com.xsbc.utils.MyInterceptor1" />
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/book/query" />
            <bean class="com.xsbc.utils.MyInterceptor2" />
        </mvc:interceptor>
    </mvc:interceptors>

九、SSM整合

9.1 创建web项目

  • 创建maven工程
  • 修改pom文件packaging=war
<packaging>war</packaging>
  • 完成maven工程web项目结构
  • 添加web项目依赖
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
  • 配置服务器运行环境

9.2 部署MyBatis

  • 添加MyBatis依赖
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.27</version>
        </dependency>
        <!-- mybatis依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>

        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
  • 创建MyBatis配置文件:mybatis-config.xml 
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

</configuration>

9.3 部署Spring、SpringMVC

1)添加依赖

    <properties>
        <spring.version>5.3.2</spring.version>
    </properties>     
    
    <!-- context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- json依赖 -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.1</version>
        </dependency>
        
        <!-- junit测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

2)创建Spring配置(多配置文件分开配置) :降低耦合度

  • spring-context.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"
       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">

    <!-- 声明使用注解配置 -->
    <context:annotation-config/>
    <!-- 声明Spring工厂注解的扫描范围 -->
    <context:component-scan base-package="com.xsbc"/>
</beans>
  • spring-mvc.xml:进行mvc相关的配置,例如静态资源配置、拦截器配置等
<?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: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/mvc 
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 声明MVC使用注解配置 --> 
    <mvc:annotation-driven/>
</beans>
  • spring-mybatis.xml:进行Spring与MyBatis整合的相关配置
<?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:aop="http://www.springframework.org/schema/aop"
       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/aop 
       http://www.springframework.org/schema/aop/spring-aop.xsd">


</beans>

 3)配置SpringMVC前端控制器

  • 在web.xml进行配置
<!-- *表示后缀名  -->
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-*.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

9.4 整合配置

1)导入spring-mybatis依赖

<!-- mybatis兼容spring的依赖 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
</dependency>

2)配置druid连接池

  • 添加druid依赖
<!-- druid连接池依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
</dependency>
  •  创建druid.properties文件并配置
druid.driver=com.mysql.jdbc.Driver
druid.url=jdbc:mysql://localhost:3306/db_2021_mybatis?characterEncoding=UTF-8
druid.username=root
druid.password=1234

### 连接池参数
druid.pool.init=2
druid.pool.minIdle=3
druid.pool.maxActive=20
druid.pool.timeout=30000
  • 在spring-mybatis.xml配置数据源
<context:property-placeholder location="classpath:druid.properties" />

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="${druid.driver}"/>
    <property name="url" value="${druid.url}" />
    <property name="username" value="${druid.username}" />
    <property name="password" value="${druid.password}" />

    <property name="initialSize" value="${druid.pool.init}" />
    <property name="minIdle" value="${druid.pool.minIdle}" />
    <property name="maxActive" value="${druid.pool.maxActive}" />
    <property name="maxWait" value="${druid.pool.timeout}" />
</bean>

3)配置SqlSessionFactory

  • 在spring-mybatis.xml配置数据源
<bean id="sqlSessionFactory" 
    class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="druidDataSource" />
    <property name="mapperLocations" value="classpath:mappers/*.xml" />
    <property name="typeAliasesPackage" value="com.xsbc.bean" />
    <property name="configLocation" value="classpath:mybatis-config.xml" />
</bean>

4)配置MapperScannerConfigurer

  • 在spring-mybatis.xml配置数据源
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    <property name="basePackage" value="com.xsbc.dao" />
</bean>

9.5 整合配置AOP

使用Spring提供的事务管理完成DAO操作的事务管理

基于注解的事务管理配置:

  • 将Spring提供的事务管理切面类配置到Spring容器
<bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druidDataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />

9.6 整合测试

1)完成User的查询操作

  • 创建实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class User {
    private int userId;
    private String userName;
    private String userPwd;
    private String userRealName;
    private String userImg;
}
  • 在DAO包中创建接口
public interface UserDAO {
    public User queryUserByName(String name);
}
  • 在mappers目录下创建映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xsbc.dao.UserDAO">

    <resultMap id="userMap" type="User">
        <id column="user_id" property="userId" />
        <result column="user_name" property="UserName" />
        <result column="user_pwd" property="userPwd" />
        <result column="user_realname" property="userRealName" />
        <result column="user_img" property="userImg" />
    </resultMap>
    <select id="queryUserByName" resultMap="userMap">
        select user_id,user_name,user_pwd,user_realname,user_img
        from users
        where user_name={userName}
    </select>
</mapper>

2)对DAO单元测试

  • 添加juint依赖
<!-- junit测试 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.3.13</version>
    <scope>test</scope>
</dependency>
  • 创建测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath*:spring-*.xml")
//@ContextConfiguration(locations={"classpath:spring-context.xml",
//        "classpath:spring-mvc.xml","classpath:spring-mybatis.xml"})
public class UserDAOTest {

    @Resource
    private UserDAO userDAO;
    @Test
    public void testQueryUserByName() {
        User user=userDAO.queryUserByName("WangWu");
        System.out.println(user);
    }
}

3)完成service层

  • 创建UserService接口
public interface UserService {

    public User checkLogin(String username, String userPwd);
}
  • 创建service实现类,并添加注解@Service
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDAO userDAO;

    public User checkLogin(String userName, String userPwd) {
        User user=userDAO.queryUserByName(userName);
        //加密
        if(user.getUserPwd().equals(userPwd)){
            return user;
        }
        return null;
    }
}
  • 创建测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath*:spring-*.xml")
public class UserServiceImplTest {

    @Resource
    private UserService userService;

    @Test
    public void testCheckLogin() {
        User user=userService.checkLogin("ZhangSan", "123123");
        assertNotNull(user);
        System.out.println(user);
    }
}

4)完成controller层

  • 创建实体类
@Controller
@RequestMapping("/user")
public class UserController {

    @Resource
    private UserService userService;

    @RequestMapping("/login")
    public String login(String userName, String userPwd, 
        HttpServletRequest request){
        User user=userService.checkLogin(userName, userPwd);
        if(user==null){
            request.setAttribute("tips","用户名或密码错误");
            return "/login.jsp";
        }
        request.getSession().setAttribute("user",user);
        return "/index.jsp";
    }
}
  • 添加jsp文件测试
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <base href="${pageContext.request.contextPath}/">
    <title>Title</title>
</head>
<body>
    <h3>登录页面</h3>
    ${tips}
    <form action="user/login" method="post">
        <p>账号:<input type="text" name="userName" /></p>
        <p>密码:<input type="text" name="userPwd" /></p>
        <p><input type="submit" value="登录" /></p>
    </form>
</body>
</html>

注意:添加<base href="${pageContext.request.contextPath}/">可以解决路径重定向再次登录的问题。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路上的追梦人

您的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值