ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SpringMVC

2021-04-18 09:31:16  阅读:223  来源: 互联网

标签:return String SpringMVC eNo ModelAndView new public


SpringMVC

文章目录

什么是SpringMVC

Spring MVC属于Spring FrameWork的一部分,是一种基于Java的实现了Web MVC设计模式的轻量级Web框架。

官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc

为什么要学习SpringMVC

Spring MVC的特点:

1.轻量级,简单易学
2.高效,基于请求响应的MVC框架

3.与Spring兼容性好,无缝结合

4.约定优于配置
5.功能强大:RESTful、数据验证、格式化、本地化、主题等

6.简洁灵活
Spring的web框架围绕DispatcherServlet[调度Servlet ]设计。

回顾MVC

MVC 架构模式

​ 高内聚低耦合

MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

  • Model(模型) - 模型代表一个存取数据的对象或 实体类对象。它也可以带有逻辑,在数据变化时更新控制器。
  • View(视图) - 视图代表模型包含的数据的可视化。
  • Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。
  • img

MVC框架要做什么事情

Controller:控制器

  1. 取得表单数据
  2. 调用业务逻辑
  3. 转向指定的页面

Model:模型

  1. 业务逻辑
  2. 保存数据的状态(持久化)

View:视图

  1. 显示视图

IDEA搭建Web项目

步骤

  1. 新建普通的Maven项目
  2. 删除Src目录作为父项目
  3. 新建子项目,添加框架支持
  • 在这里插入图片描述

  • 在这里插入图片描述

问题描述

​ 若启动项目,tomcat正常访问,但对于Controller控制器中映射地址的访问无效,可能是打包时jar包未导入进去。

​ 组件扫描器未进行生效。

解决方案

手动导入

​ 1、选中项目,点击项目结构

  • 在这里插入图片描述

​ 2、在WEB-INF目录下,新建lib文件夹

  • 在这里插入图片描述

3、选中lib目录,选择所要导入的jar包,点击应用,重启tomcat

  • 在这里插入图片描述

回顾Servlet

​ 配置环境、编码、测试

实现步骤

  1. 创建Web项目

  2. 导入依赖

    <dependencies>
            <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>4.0.1</version>
                <scope>provided</scope>
            </dependency>
            <!-- https://mvnrepository.com/artifact/javax.servlet/jsp-api -->
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jsp-api</artifactId>
                <version>2.0</version>
                <scope>provided</scope>
            </dependency>
            <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl -->
            <dependency>
                <groupId>javax.servlet.jsp.jstl</groupId>
                <artifactId>jstl</artifactId>
                <version>1.2</version>
            </dependency>
        </dependencies>
    
  3. 编写Servlet

    继承HttpServlet,重写get和post方法

    package com.rui.controller;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    public class UserServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        				throws ServletException, IOException {
            req.setAttribute("userName", "李四");
            req.getRequestDispatcher("/WEB-INF/jsp/show.jsp").forward(req, resp);
        }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        														throws ServletException, IOException {
            doGet(req, resp);
        }
        
    }
    
    
    1. 编写视图
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    	${userName}
    </body>
    </html>
    
    1. 启动tomcat测试

/ 和 /* 的区别

总结

​ 两者都可以匹配任何资源,只不过两者的匹配的优先级是不一样的;当请求资源与其它Servlet都无法匹配的时候,/所配置的Servlet才会匹配

注意点:

在Tomcat中conf/web.xml中有关于/和.jsp页面处理的Servlet,当自己所配的web.xml文件中配置/时,

会使Tomcat中的DefaultServlet无法访问,导致静态资源无法访问,因此在SpingMVC配置文件中要开启处理静态资源的开关。

重点:

/ 能匹配路径型URL,不能匹配后缀型URL(除静态资源类后缀的,例:.png 、.jpg 、.html)

/* 能匹配任何类型URL,在配置视图的时候尽量用/这种方式。

即:使用 / ,DispatcherServlet对于 .jsp 等带有后缀的资源不进行拦截。

​ 而使用 /* DispatcherServlet会对其进行拦截,查找对应的Controller控制器,查找不到则报404错误!

SpringMVC中解决静态资源访问问题的两种方式

  • 使用tomcat的默认Servlet进行静态资源的处理

     <mvc:default-servlet-handler/>
    
  • 声明静态资源,进行特殊处理

    <!--
    mapping:映射
    location:本地资源路径,注意必须是webapp根目录下的路径。
    两个*,它表示映射resources/下所有的URL,包括子路径(即接多个/)
    -->
    <mvc:resources mapping="/photo/**" location="/photo/"/>
    

SpringMVC执行流程

流程图示

  • 在这里插入图片描述

流程描述

  1. DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。

    • 我们假设请求的url为 : http://localhost:8080/SpringMVC/test

      如上url拆分成三部分:
      http://localhost:8080服务器域名

      SpringMVC部署在服务器上的web站点

      test表示控制器的映射地址

      通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的test对应的控制器。

  2. HandlerMapping为处理器映射。DispatcherServlet调用
    HandlerMapping,HandlerMapping根据请求url查找Handler。

  3. HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:test。

  4. HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。

  5. HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。

  6. Handler让具体的Controller执行。

  7. Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。

  8. HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。

  9. DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。

  10. 视图解析器将解析的逻辑视图名传给DispatcherServlet。

  11. DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。

  12. 最终视图呈现给用户。

SpringMVC的第一个程序

XML的方式开发

  1. 构建web项目,导入依赖

  2. 配置中央调度器(DispatchServlet)

    <?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-MVC.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>
    
  3. 编写控制器(Controller)

    1. 实现Controller接口,重写handleRequest()方法
    package com.rui.controller;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class StudentServlet implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
                                          HttpServletResponse httpServletResponse) throws Exception {
            ModelAndView  mv = new ModelAndView();
            mv.addObject("username", "学生:张三");
            mv.setViewName("/WEB-INF/jsp/show.jsp");
            return null;
        }
    }
    
    package com.rui.controller;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class UserServlet implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
                                          HttpServletResponse httpServletResponse) throws Exception {
    
            ModelAndView  mv = new ModelAndView();
            mv.addObject("username", "用户:lisi");
            mv.setViewName("/WEB-INF/jsp/show.jsp");
    
            return mv;
        }
    }
    
  4. 编写Spring-MVC的配置,声明控制器对象

    1. 不需要额外声明BeanNameUrlHandlerMapping和SimpleControllerHandlerAdapter。
    2. Debug模式下,调试发现SpringMVC初始化时自动创建。
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="/getUser" class="com.rui.controller.UserServlet"/>
    
        <bean id="/getStudent" class="com.rui.controller.StudentServlet"/>
    </beans>
    
  5. 编写视图界面,测试

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    		${username}
    </body>
    </html>
    

总结:

以上代码存在很多缺点

	1.	一个控制器(Controller)只能有一个方法,返回值固定。
	2.	每创建一个控制器,则需要在SpringMVC的配置文件中进行配置。
	3.	视图路径,存在冗余。

视图解析器

​ 解决视图路径冗余问题

使用步骤

  1. 在SpringMVC的配置文件中声明视图解析器
<bean id="view" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
     <property name="prefix" value="/WEB-INF/jsp/"/>
     <property name="suffix" value=".jsp"/>
</bean>
  1. 控制器(Controller)中,编写的响应地址可以省略前缀和后缀

    package com.rui.controller;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class UserServlet implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
                                          HttpServletResponse httpServletResponse) throws Exception {
    
            ModelAndView  mv = new ModelAndView();
            mv.addObject("username", "用户:lisi");
            mv.setViewName("show");
    
            return mv;
        }
    }
    
  2. 视图解析器原理

    内部实现是进行字符串的拼接

  3. 特定情况下,不想让视图解析器起作用

    1. forward和redirect都是关键字, 有一个共同的特点不和视图解析器一同工作(不加关键字:默认为转发操作)
    package com.rui.controller;
    
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.Controller;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class UserServlet implements Controller {
        @Override
        public ModelAndView handleRequest(HttpServletRequest httpServletRequest,
                                          HttpServletResponse httpServletResponse) throws Exception {
    
            ModelAndView  mv = new ModelAndView();
            mv.addObject("username", "用户:lisi");
            mv.setViewName("forward:/WEB-INF/jsp/show.jsp");
    
            return mv;
        }
    }
    

注解式开发

​ 解决控制器类单一方法、特定返回值的问题

@Controller

  1. 作用:声明的类为控制器类

    package com.rui.controller;
    
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class UserServlet {
        
    }
    
  2. 使用:需要声明组件扫描器

    <?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 
           https://www.springframework.org/schema/context/spring-context.xsd
            ">
    
        <context:component-scan base-package="com.rui"/>
    
    </beans>
    

@RequestMapping

  1. 使用方式(类上、方法上)

    1. 声明在类上面,表示模块名称
    2. 声明在方法上面,表示映射的地址名称
    3. 则请求地址为:http://localhost:8080/项目名/模块名/请求地址
    package com.rui.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.servlet.ModelAndView;
    
    @Controller
    @RequestMapping("/user")
    public class UserServlet {
    
        @RequestMapping(value = "/getName",method = RequestMethod.GET)
        public ModelAndView showName(){
            ModelAndView mv = new ModelAndView();
            mv.addObject("username", "username:lisi");
            mv.setViewName("showName");
            return mv;
        }
    
        @RequestMapping("/getAge")
        public ModelAndView showAge(){
            ModelAndView mv = new ModelAndView();
            mv.addObject("age", "age:21");
            mv.setViewName("showAge");
            return mv;
        }
    
        @RequestMapping("/forward")
        public ModelAndView forward(){
            ModelAndView mv = new ModelAndView();
            mv.setViewName("forward:index.jsp");
            return mv;
        }
    
    }
    
  2. 属性

    ​ 不加method属性,请求不受限制,可以接受任意请求方式的请求

    1. value/path属性

      声明映射地址

      @RequestMapping("/forward")
      
    2. method属性

      声明请求方式类型

      @RequestMapping(value = "/forward",method = RequestMethod.GET)
      

    存在问题:

    1. 声明请求类型,代码繁琐
    2. 返回值资源浪费问题(有时不需要model,有时不需要view,使用ModelAndView浪费资源)
  3. 解决声明请求类型代码繁琐的问题

    @RequestMapping注解衍生出5中明确请求类型的mapping注解

    ​ @GetMapping

    ​ @PostMapping

    ​ @PutMapping

    ​ @DeleteMapping

    ​ @PatchMapping

@RequestParam

逐个接收请求参数中, 解决请求中参数名形参名不一样的问题

  1. 使用方式:

     @RequestMapping("/forward")
    public ModelAndView forward(@RequestParam(value = "name",required = false) String name){
      ModelAndView mv = new ModelAndView();
      mv.setViewName("forward:index.jsp");
      return mv;
    }
    
  2. 属性:

    1. value 请求中的参数名称
    2. required 是一个boolean,默认是true
      1. true:表示请求中必须包含此参数。

@ResponseBody

​ 注解 @ResponseBody,使用在控制层(controller)的方法上

作用:

  1. 将方法的返回值,以特定的格式写入到response的body区域,进而将数据返回给客户端。

  2. 当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象。

  3. 如果返回值是字符串,那么直接将字符串写到客户端;如果是一个对象,会将对象转化为json串,然后写到客户端。

    @GetMapping(value = "/getUser",produces = "text/html;charset=utf-8")
    @ResponseBody
    public String getUser(){
        User user = new User(1,"李四");
        return user.toString();
    }
    

注意编码格式

  1. 如果返回对象,按utf-8编码。

  2. 如果返回String,默认按iso8859-1编码。

  3. 页面可能出现乱码。

  4. 因此在注解中我们可以手动修改编码格式,例如@RequestMapping(value="/hello",produces=“text/html;charset=utf-8”),前面是请求的路径,后面是编码格式

@RestController

是@ResponseBody和@Controller的组合

@ControllerAdvice

  • 通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置。

  • 注解了@ControllerAdvice的类的方法可以使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上。

    • @ExceptionHandler:用于全局处理控制器里的异常。
    • @InitBinder:用来设置WebDataBinder,用于自动绑定前台请求参数到Model中。
    • @ModelAttribute:本来作用是绑定键值对到Model中,此处让全局的@RequestMapping都能获得在此处设置的键值对
  • @ControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上。

@ExceptionHandler

  • 基本使用方法
    • 方法加上@ExceptionHandler注解,这个方法就会处理类中其他方法(被@RequestMapping注解)抛出的异常
  • 注解的参数
    • @ExceptionHandler注解中可以添加参数,参数是某个异常类的class,代表这个方法专门处理该类异常
  • 就近原则
    • 当异常发生时,Spring会选择最接近抛出异常的处理方法

联合使用:全局异常处理,可以跳转指定的错误页面,也可以采用@ResponseBody,返回字符串

package com.rui.controller.advice;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(NullPointerException.class)
    public String isNullEmp(){
        return "empIsNull";
    }
    
    @ExceptionHandler(Exception.class)
    public String isNullEmp(Exception ex){
        System.out.println(ex.getMessage());
        return "error";
    }
    
}

处理器方法的形参

​ 前端数据的接收

形参类型

  1. HttpServletRequest
  2. HttpServletResponse
  3. HttpSession
  4. 用户提交的数据

框架自动进行赋值,方法中可以直接使用

请求参数的接收方式

  1. 逐个接收

    1. 处理器(控制器)方法的形参名和请求中参数名必须一致。
    2. 同名的请求参数赋值给同名的形参
    @RequestMapping("/forward")
    public ModelAndView forward(String name,String age){
        ModelAndView mv = new ModelAndView();
        System.out.println(name);
        mv.setViewName("forward:index.jsp?name="+name);
        return mv;
    }
    
  2. 对象接收

    @RequestMapping("/forward")
    public ModelAndView forward(User user){
        ModelAndView mv = new ModelAndView();
        System.out.println(name);
        mv.setViewName("forward:index.jsp?name="+name);
        return mv;
    }
    

返回值类型

​ 解决返回值资源浪费问题

ModelAndView

  1. 若处理器方法处理完后,需要跳转到其它资源,且又要在跳转的资源间传递数据

    @RequestMapping(value = "/getName",method = RequestMethod.GET)
    public ModelAndView showName(){
        ModelAndView mv = new ModelAndView();
        mv.addObject("username", "username:lisi");
        mv.setViewName("showName");
        return mv;
    }
    

String

  1. 处理器方法返回的字符串可以指定逻辑视图名,通过视图解析器解析可以将其转换为物理视图地址

  2. 也可以通过@ResponseBody,返回字符串

    @GetMapping(value = "/getIndex")
    public String getUserString(){
        return "redirect:index.jsp";
    }
    
    @GetMapping(value = "/getUserString",produces = "text/html;charset=utf-8")
    @ResponseBody
    public String getUserString(){
        User user = new User(1,"李四");
        return user.toString();
    }
    

void

  1. 若处理器对请求处理后,无需跳转到其它任何资源。例:AJAX响应

  2. 处理器方法返回值void,不能表示数据,也没有视图。

  3. 可以通过使用HttpServletResponse的输出对象,把数据输出到浏览器

    @PostMapping("/getUserJson")
    public void getUserJson(HttpServletResponse response) throws IOException {
        User user = new User(1,"李四");
        ObjectMapper om = new ObjectMapper();
        String userJson = om.writeValueAsString(user);
        PrintWriter out = response.getWriter();
        out.print(userJson);
        out.flush();
        out.close();
    }
    

Object

  1. 返回的对象不是作为逻辑视图出现的,而是作为直接在页面显示的数据出现的。

  2. 返回对象,需要使用@ResponseBody注解,将转换后的JSON数据放入到响应体中

    处理对象到json格式,需要消息转化器、json依赖

  • <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.10.0</version>
    </dependency>
    
  • <mvc:annotation-driven/>
    

    执行过程源代码分析

  • 没有加入注解驱动标签时的状态
    org.springframework.http.converter.ByteArrayHttpMessageConverter 
    org.springframework.http.converter.StringHttpMessageConverter
    org.springframework.http.converter.xml.SourceHttpMessageConverter
    org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
    
    
    加入注解驱动标签时的状态
    org.springframework.http.converter.ByteArrayHttpMessageConverter
    org.springframework.http.converter.StringHttpMessageConverter
    org.springframework.http.converter.ResourceHttpMessageConverter
    org.springframework.http.converter.ResourceRegionHttpMessageConverter
    org.springframework.http.converter.xml.SourceHttpMessageConverter 
    org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter 
    org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
    org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
    

中文乱码问题

解决方案

创建过滤器,进行请求、响应字符集过滤!

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

源码分析

  • @Nullable
    private String encoding;
    
    private boolean forceRequestEncoding = false;
    
    private boolean forceResponseEncoding = false;
    
  • String encoding = getEncoding();
    if (encoding != null) {
        if (isForceRequestEncoding() || request.getCharacterEncoding() == null) {
            request.setCharacterEncoding(encoding);
        }
        if (isForceResponseEncoding()) {
            response.setCharacterEncoding(encoding);
        }
    }
    filterChain.doFilter(request, response);
    

RestFul风格

它是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件,它主要用于客户端和服务端交互类的软件。基于这个风格设计的软件可以更简介,更有层次,更易于实现缓存等机制

状态转化

HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE

分别对应四种基本操作:

1.	GET用来获取资源
2.	POST用来新建资源
3.	PUT用来更新资源
4.	DELETE用来删除资源

如何设计RESTful应用程序的API

路径设计:数据库设计完毕之后,基本上就可以确定有哪些资源要进行操作,相对应的路径也可以设计出来。

动词设计:也就是针对资源的具体操作类型,有HTTP动词表示,常用的HTTP动词如下:POST、DELETE、PUT、GET

SpringMVC对RESTful的支持

RESTful的URL路径变量

URL-PATTERN:设置为/,方便拦截RESTful请求。

@PathVariable:可以解析出来URL中的模板变量({id}/{name})

RESTful的CRUD

@RequestMapping:通过设置method属性的CRUD,可以将同一个URL映射不同HandlerMethod方法上。

@GetMapping、@PostMapping、@PutMapping、@DeleteMapping注解同@RequestMapping注解的method属性设置。

RESTful的资源表述

RESTful服务中一个重要的特性就是一种资源可以有多种表现形式,在SpringMvc中可以使用ContentNegotiatingManager这个内容协商管理器来实现这种方式。

使用

@PostMapping("/add/{a}/{b}")
public String add(@PathVariable int a,@PathVariable int b, Model model) throws IOException {
    model.addAttribute("result", a+b);
    return "test";
}

@GetMapping("/add/{a}/{b}")
public String delete(@PathVariable int a,@PathVariable int b, Model model) throws IOException {
    model.addAttribute("result", a-b);
    return "test";
}

整合SSM

搭建环境

  1. 数据库

    create DATABASE springmvc;
    
    use springmvc;
    
    drop table if  EXISTS emp;
    
    CREATE TABLE emp(
    	eNo int(10) primary KEY COMMENT '员工编号',
    	eName varchar(255) not NULL COMMENT '员工名',
    	sal double(11,2) not NULL COMMENT '薪资'
    )ENGINE=INNODB DEFAULT charset=utf8
    
    INSERT into emp(eNo,eName,sal) VALUES
    (1,'zhangsan',5000.0),
    (2,'lisi',4352.0),
    (3,'king',10000.0);
    
  2. 创建maven项目,构建为Web项目,导入依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.rui</groupId>
        <artifactId>sprngmvc-ssm</artifactId>
        <version>1.0-SNAPSHOT</version>
    
    <!--
    依赖:
    	junit,数据库驱动,连接池,servlet ,jsp,mybatis,
    	spring,mybatis,mybatis-spring,spring-web,spring-jdbc
    	jackson,aspectj(aop)
    -->
        <dependencies>
             <!-- junit -->
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
             <version>4.13.1</version>
             <scope>test</scope>
         </dependency>
         <!-- 数据库 -->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <version>5.1.47</version>
         </dependency>
         <!--数据库连接池-->
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>druid</artifactId>
             <version>1.2.5</version>
         </dependency>
         <!-- servlet-jsp -->
         <dependency>
             <groupId>javax.servlet</groupId>
             <artifactId>javax.servlet-api</artifactId>
             <version>4.0.1</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>javax.servlet.jsp</groupId>
             <artifactId>javax.servlet.jsp-api</artifactId>
             <version>2.3.3</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>javax.servlet.jsp.jstl</groupId>
             <artifactId>jstl-api</artifactId>
             <version>1.2</version>
         </dependency>
         <dependency>
             <groupId>org.glassfish.web</groupId>
             <artifactId>jstl-impl</artifactId>
             <version>1.2</version>
             <scope>runtime</scope>
         </dependency>
         <!-- mybatis -->
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
             <version>3.5.6</version>
         </dependency>
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis-spring</artifactId>
             <version>2.0.6</version>
         </dependency>
         <!-- spring -->
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-webmvc</artifactId>
             <version>5.3.5</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-jdbc</artifactId>
             <version>5.3.5</version>
         </dependency>
         <!--aspectj依赖-->
         <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-aspects</artifactId>
             <version>5.2.5.RELEASE</version>
         </dependency>
         <!--jackson-->
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
             <version>2.9.0</version>
         </dependency>
         <!--文件下载-->
         <dependency>
             <groupId>commons-fileupload</groupId>
             <artifactId>commons-fileupload</artifactId>
             <version>1.4</version>
         </dependency>
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
             <version>2.8.0</version>
         </dependency>
         <!-- 邮件 -->
         <dependency>
             <groupId>javax.mail</groupId>
             <artifactId>mail</artifactId>
             <version>1.5.0-b01</version>
         </dependency>
        </dependencies>
    
        <build>
            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.properties</include>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
            </resources>
        </build>
    
    </project>
    
  3. 注册中央调度器,字符集过滤器

    <?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-MVC.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>
    
        <filter>
            <filter-name>charsetEncoding</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>charsetEncoding</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <session-config>
            <session-timeout>15</session-timeout>
        </session-config>
        
    </web-app>
    

编码

  1. 实体类(对应数据库)

    1. package com.rui.entity;
      
      public class Emp {
      
          private int eNo;
          private String eName;
          private double sal;
      
          public Emp() {
          }
      
          public Emp(int eNo, String eName, double sal) {
              this.eNo = eNo;
              this.eName = eName;
              this.sal = sal;
          }
      
          public int geteNo() {
              return eNo;
          }
      
          public void seteNo(int eNo) {
              this.eNo = eNo;
          }
      
          public String geteName() {
              return eName;
          }
      
          public void seteName(String eName) {
              this.eName = eName;
          }
      
          public double getSal() {
              return sal;
          }
      
          public void setSal(double sal) {
              this.sal = sal;
          }
      
          @Override
          public String toString() {
              return "Emp{" +
                      "eNo=" + eNo +
                      ", eName='" + eName + '\'' +
                      ", sal=" + sal +
                      '}';
          }
      }
      
  2. dao层(dao层接口,接口对应的mapper文件,mybatis的主配置文件,spring-mybatis的配置文件,数据库配置文件)

    1. package com.rui.dao;
      
      import com.rui.entity.Emp;
      import org.apache.ibatis.annotations.Param;
      
      import java.util.List;
      
      public interface EmpDao {
      
          //查询一个员工
          Emp toIdSelectEmp(@Param("eNo") int eNo);
          //删除一个员工
          int toIdDeleteEmp(@Param("eNo") int eNo);
          //更新一个员工
          int toIdUpdateEmp(Emp emp);
          //添加一个员工
          int addEmp(Emp emp);
          //展示所有员工
          List<Emp> selectAllEmp();
      
      }
      
    2. <?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.rui.dao.EmpDao">
      
      
          <select id="toIdSelectEmp" resultType="emp">
              select * from emp where eNo =#{eNo}
          </select>
      
          <delete id="toIdDeleteEmp" >
              delete from emp where eNo =#{eNo}
          </delete>
      
          <insert id="addEmp">
              insert into emp(eNo,eName,sal) values(#{eNo},#{eName},#{sal})
          </insert>
      
          <update id="toIdUpdateEmp">
              update emp set eName=#{eName},sal=#{sal} where eNo =#{eNo}
          </update>
      
          <select id="selectAllEmp" resultType="emp">
              select * from emp;
          </select>
      </mapper>
      
    3. <?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>
      
          <settings>
              <setting name="logImpl" value="STDOUT_LOGGING"/>
          </settings>
      
          <typeAliases>
              <package name="com.rui.entity"/>
          </typeAliases>
      
          <mappers>
              <package name="com.rui.dao"/>
          </mappers>
      
      </configuration>
      
    4. <?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 https://www.springframework.org/schema/context/spring-context.xsd">
      
          <!--配置数据源-->
          <context:property-placeholder location="classpath:jdbc.properties" />
          <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
                init-method="init" destroy-method="close">
              <property name="driverClassName" value="${jdbc.driver}"/>
              <property name="url" value="${jdbc.url}" />
              <property name="username" value="${jdbc.username}"/>
              <property name="password" value="${jdbc.password}" />
              <property name="maxActive" value="${jdbc.maxActive}" />
          </bean>
      
          <!--定义sqlSessionFactory对象-->
          <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
              <property name="dataSource" ref="dataSource" />
              <property name="configLocation" value="classpath:mybatis-config.xml" />
          </bean>
          <!--定义Mapper扫描配置器-->
          <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
              <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
              <property name="basePackage" value="com.rui.dao"/>
          </bean>
          
      </beans>
      
    5. jdbc.driver=com.mysql.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/springmvc?useSSL=false&useUnicode=true&characterEncoding=UTF-8
      jdbc.username=root
      jdbc.password=guo12345
      jdbc.maxActive=20
      
  3. service层(接口,实现类,spring配置文件(扫描组件)),service层调dao层,进行组合

    1. package com.rui.service;
      
      import com.rui.entity.Emp;
      import java.util.List;
      
      public interface EmpService {
      
          Emp toIdSelectEmp(int eNo);
      
          int toIdDeleteEmp(int eNo);
      
          int toIdUpdateEmp(Emp emp);
      
          int addEmp(Emp emp);
      
          List<Emp> selectAllEmp();
      }
      
    2. package com.rui.service.impl;
      
      import com.rui.dao.EmpDao;
      import com.rui.entity.Emp;
      import com.rui.service.EmpService;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      @Service
      public class EmpServiceImpl implements EmpService {
      
          @Autowired
          private EmpDao empDao;
      
          public void setEmpDao(EmpDao empDao) {
              this.empDao = empDao;
          }
      
          @Override
          public Emp toIdSelectEmp(int eNo) {
              return empDao.toIdSelectEmp(eNo);
          }
      
          @Override
          public int toIdDeleteEmp(int eNo) {
              return empDao.toIdDeleteEmp(eNo);
          }
      
          @Override
          public int toIdUpdateEmp(Emp emp) {
              return empDao.toIdUpdateEmp(emp);
          }
      
          @Override
          public int addEmp(Emp emp) {
              return empDao.addEmp(emp);
          }
      
          @Override
          public List<Emp> selectAllEmp() {
              return empDao.selectAllEmp();
          }
      }
      
    3. <?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 
             https://www.springframework.org/schema/context/spring-context.xsd">
      
          <context:component-scan base-package="com.rui.service"/>
      
      </beans>
      
  4. controller层(spring-mvc配置文件,控制器编写),controller层调service层,进行组合

    1. 首页

      1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <html>
          <head>
            <title> 员工系统 </title>
          </head>
          <body>
            <a href="${pageContext.request.contextPath}/allEmps">进入员工系统</a>
          </body>
        </html>
        
    2. 查询所有员工,跳转显示

      1. @GetMapping("/allEmps")
        public ModelAndView allEmps(){
            ModelAndView mv = new ModelAndView();
            List<Emp> emps = empService.selectAllEmp();
            mv.addObject("emps", emps);
            mv.setViewName("empList");
            return mv;
        }
        
      2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
        <html>
        <head>
            <title>员工列表</title>
        </head>
        <body>
        
        <a href="${pageContext.request.contextPath}/toAddPage">添加</a>
        <br>
        <table border="1" >
            <tr>
                <td>员工编号</td>
                <td>员工姓名</td>
                <td>员工薪资</td>
                <td colspan="2">操作</td>
            </tr>
            <c:forEach var="emp" items="${emps}">
                <tr>
                    <td>${emp.eNo}</td>
                    <td>${emp.eName}</td>
                    <td>${emp.sal}</td>
                    <td><a href="${pageContext.request.contextPath}/toUpdatePage?eNo=${emp.eNo}">修改</a></td>
                    <td><a href="${pageContext.request.contextPath}/delete?eNo=${emp.eNo}">删除</a></td>
                </tr>
            </c:forEach>
        </table>
        
        </body>
        </html>
        
    3. 添加员工

      1. @GetMapping("/toAddPage")
        public String toAddPage(){
            return "add";
        }
        
        @PostMapping("/add")
        public String addEmp(@RequestParam("eNo")int eNo,@RequestParam("eName")String eName,@RequestParam("sal")double sal){
            Emp emp = new Emp(eNo,eName,sal);
            empService.addEmp(emp);
            return "redirect:/allEmps";
        }
        
      2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <html>
        <head>
            <title>添加</title>
        </head>
        <body>
            <form action="${pageContext.request.contextPath}/add" method="post">
                编号<input name="eNo" type="text"/><br>
                姓名<input name="eName" type="text"/><br>
                薪资<input name="sal" type="text"/><br>
                <input  type="submit" value="添加"/>
            </form>
        </body>
        </html>
        
    4. 更新员工信息

      1. @GetMapping("/toUpdatePage")
        public String toUpdatePage(@RequestParam("eNo")int eNo,Model model){
            Emp emp = empService.toIdSelectEmp(eNo);
            model.addAttribute("emp", emp);
            return "update";
        }
        @PostMapping("/update")
        public String updateEmp(@RequestParam("eNo")int eNo,@RequestParam("eName")String eName,@RequestParam("sal")double sal){
            Emp emp = new Emp(eNo,eName,sal);
            empService.toIdUpdateEmp(emp);
            return "redirect:/allEmps";
        }
        
      2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
        <html>
        <head>
            <title>更新</title>
        </head>
        <body>
            <form action="${pageContext.request.contextPath}/update" method="post">
                编号<input name="eNo" type="text" value="${emp.eNo}" readonly/><br>
                姓名<input name="eName" type="text" value="${emp.eName}"/><br>
                薪资<input name="sal" type="text" value="${emp.sal}"/><br>
                <input  type="submit" value="添加"/>
            </form>
        </body>
        </html>
        
    5. 删除员工

      1. @GetMapping("/delete")
        public String deleteEmp(@RequestParam("eNo")int eNo){
            empService.toIdDeleteEmp(eNo);
            return "redirect:/allEmps";
        }
        
    6. spring-mvc配置

      1. <?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">
        
            <context:component-scan base-package="com.rui.controller"/>
            <!--视图解析器-->
            <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
                <property name="prefix" value="/WEB-INF/jsp/"/>
                <property name="suffix" value=".jsp"/>
            </bean>
            <!--处理静态资源-->
            <mvc:default-servlet-handler/>
            
            <mvc:annotation-driven/>
        
        </beans>
        
  5. 整合spring-*的配置文件,applicationContext.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
          <import resource="classpath:spring-mvc.xml"/>
          <import resource="classpath:spring-dao.xml"/>
          <import resource="classpath:spring-service.xml"/>
      
      </beans>
      

错误及解决方案

Jstl依赖导入,jsp中引入时爆红问题!

解决方法:导入jsp-api,另外导入jstl-impl

  • <dependency>
        <groupId>org.glassfish.web</groupId>
        <artifactId>jstl-impl</artifactId>
        <version>1.2</version>
        <scope>runtime</scope>
    </dependency>
    

Jackson包导入可能出现的问题

​ org.apache.catalina.startup.ContextConfig.processAnnotationsJar Unable to process Jar entry [module-info.class] from Jar

解决方法:

​ 在Maven本地仓库中找到相应的jar包,使用压缩软件打开,删除module-info.class

拦截器

​ 作用是拦截指定的用户请求,并进行相应的预处理与后处理。

拦截器的使用

自定义拦截器,需要实现HandlerInterceptor接口(三个默认实现方法)。

boolean preHandle(request,response, Object handler)

  • 处理器方法执行之前执行。若为true,则紧接着会执行处理器方法,
  • 且会将afterCompletion()方法放入到一个专门的方法栈中等待执行。

void postHandle(request,response, Object handler,modelAndView)

  • 该方法在处理器方法执行之后执行。处理器方法若最终未被执行,则该方法不会执行。
  • 由于该方法是在处理器方法执行完后执行,且该方法参数中包含ModelAndView,即该方法可以修改处理器方法的处理结果数据,且可以修改跳转方向。

void afterCompletion(request,response, Object handler, Exception ex)

  • 当preHandle()方法返回true时,会将该方法放到专门的方法栈中,等到对请求进行响应的所有工作完成之后才执行该方法。
  • 即该方法是在中央调度器渲染(数据填充)了响应页面之后执行的,此时对ModelAndView再操作也对响应无济于事
  • afterCompletion最后执行的方法,清除资源,例如在Controller方法中加入数据

使用

  • package com.rui.controller.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 authorityVerify implements HandlerInterceptor {
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            if("张三".equals("张三")){
                System.out.println("处理器1方法执行前");
                return true;
            }else{
                System.out.println("处理器1方法执行前");
                return false;
            }
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            System.out.println("处理器1方法执行后");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            System.out.println("页面1渲染执行后");
        }
    }
    

    注册拦截器

  • <!--    <mvc:mapping/>用于指定当前所注册的拦截器可以拦截的请求路径,而/**表示拦截所有请求。-->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.rui.controller.interceptor.authorityVerify"/>
        </mvc:interceptor>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.rui.controller.interceptor.authorityVerify1"/>
        </mvc:interceptor>
    </mvc:interceptors>
    

拦截器的执行流程

在这里插入图片描述

多个拦截器

执行结果
在这里插入图片描述

编程注意事项

避免重复性“造轮子”

例如:方法的重载

  • 数据库关闭资源(以下代码造成了重复性“造轮子”)

    public static void close(ResultSet rs, Statement ps, Connection conn){
        if (rs == null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps == null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn == null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void close(Statement ps, Connection conn){
        if (ps == null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn == null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 优化(避免了重复性“造轮子”)

    public static void close(ResultSet rs, Statement ps, Connection conn){
        if (rs == null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps == null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn == null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    
    public static void close(Statement ps, Connection conn){
     close(null,ps,conn);
    }
    

避免多余分工

对于一个类的相关类,若相关类只作用于该类,可以定义为内部类,降低项目的复杂度。
可以避免查看源码时不停的跳转

避免火箭式开发

​ 多层嵌套,可读性极差,可以分开判断(不需要太考虑效率的问题)

  • 	public boolean verifyUser{
            char[] chars = null ;
            if(user != null){
                if(user.name.equals("张三")){
                    chars = user.name.toCharArray();
                    for(char a :chars){
                        if(a == 'a'){
                            System.out.print(a);
                        }
                    }
             }else{
                    return false;
             }else{
                    return false;
             }
            return true;
        }
    
    
        public boolean verifyUser{
            char[] chars = null ;
            if(user == null){
                return false;
            }
            if(user.name.equals("张三")){
                chars = user.name.toCharArray();
            }else{
                return false;
            }
            for(char a :chars){
                if(a == 'a'){
                    System.out.print(a);
                }
            }
            return ture;
        }
    

注:构建项目->由上向下、排查->由下向上

扩展

文件上传与下载

  1. 导包

    <!--文件下载-->
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.4</version>
            </dependency>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.8.0</version>
            </dependency>
    
  2. 设置表单类型及提交方式

    1. 表单类型:multipart/form-data
    2. 提交方式(必须是post请求,不能为get请求)
    <form action="${pageContext.request.contextPath }/fileUpload2" method="post" enctype="multipart/form-data">
        文件:<input type="file" name="file"/> <br>
        <input type="submit" value="上传"/>
    </form>
    
  3. 若使用SpringMVC实现,需要配置

    <!-- 用于文件上传、下载的配置 -->
    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="utf-8"></property>
        <property name="maxUploadSize" value="2097152"></property>
    </bean>
    

第三方jar包实现

  • 上传

  • public class RegisterServlet extends HttpServlet {
    	protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
            // 判断请求是否为multipart请求
            if( !ServletFileUpload.isMultipartContent(request) ) {
                throw new RuntimeException("当前请求不支持文件上传");
            }
            try {
                // 创建一个FileItem工厂
                DiskFileItemFactory factory = new DiskFileItemFactory();
    
                // 设置使用临时文件的边界值,大于该值,上传文件会先保存在临时文件中
                //否则,上传文件将直接写入到内存。
                // 单位:字节。本例设置边界值为1M
                factory.setSizeThreshold(1024 * 1024 * 1);
    
                // 设置临时文件
                String tempPath = this.getServletContext().getRealPath("/temp");
                File temp = new File(tempPath);
                factory.setRepository(temp);
    
                // 创建文件上传核心组件
                ServletFileUpload upload = new ServletFileUpload(factory);
    
                // 设置每一个item的头部字符编码,其可以解决文件名的中文乱码问题
                upload.setHeaderEncoding("UTF-8");
    
                // 设置单个上传文件的最大边界值为2M
                upload.setFileSizeMax(1024 * 1024 * 2);
    
                // 设置一次上传所有文件的总和最大值为5M(对于上传多个文件时起作用)
                upload.setSizeMax(1024 * 1024 * 5);
    
                // 解析请求,获取到所有的item
                List<FileItem> items = upload.parseRequest(request);
                // 遍历items
                for (FileItem item : items) {
                    if(item.isFormField()) {   // 若item为普通表单项
                        String fieldName = item.getFieldName();  // 获取表单项名称
                        String fieldValue = item.getString("UTF-8"); // 获取表单项的值
                    } else {   // 若item为文件表单项
                        String fileName = item.getName();    // 获取上传文件原始名称
                        fileName = System.currentTimeMillis() + fileName;
                        // 获取输入流,其中有上传文件的内容
                        InputStream is = item.getInputStream();
                        // 获取文件保存在服务器的路径
                        String path =this.getServletContext().getRealPath("/file");
                        // 若该目录不存在,则创建这个目录
                        File dirFile = new File(path);
                        if (!dirFile.exists()) {
                            dirFile.mkdirs();
                        }
    
                        // 创建目标文件,将来用于保存上传文件
                        File descFile = new File(path, fileName);
                        // 创建文件输出流
                        OutputStream os = new FileOutputStream(descFile);
                        // 将输入流中的数据写入到输出流中
                        int len = -1;
                        byte[] buf = new byte[1024];
                        while((len = is.read(buf)) != -1) {
                            os.write(buf, 0, len);
                        }
    
                        // 关闭流
                        os.close();
                        is.close();
    
                        // 删除临时文件
                        item.delete();
                    }
                }
            } catch (FileUploadException e) {
                e.printStackTrace();
            }
    
        }
    
    }
    

下载

  • public class DownloadServlet extends HttpServlet {
    	protected void doGet(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		
    		String fileName = "桌面.jpg";
    		
    		// 打散:按当前的字符编码进行打散
    		byte[] bytes = fileName.getBytes("UTF-8");
    		// 组装:按目标字符编码进行组装
    		fileName = new String(bytes, "ISO8859-1");
    		
    		// 修改响应的头部属性content-disposition值为attachment
    		response.setHeader("content-disposition", "attachment;filename=" + fileName);
    		
    		// 获取连接服务端资源文件的输入流
    		InputStream is = this.getServletContext().getResourceAsStream("/resources/aaa.jpg");
    		// 获取输出流 
    		ServletOutputStream os = response.getOutputStream();
    		// 将输入流中的数据写入到输出流中
    		int len = -1;
    		byte[] buf = new byte[1024];
    		while((len = is.read(buf)) != -1) {
    			os.write(buf, 0, len);
    		}
    		
    		// 关闭流
    		os.close();
    		is.close();
    	}
    

servlet3.0新特性

上传

  • @MultipartConfig
    public class LoadupServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // 获取服务端保存上传文件的目录路径
            String path = this.getServletContext().getRealPath("/file");
            // 从请求中获取Multipart请求中的上传文件“部分”对象
            request.setCharacterEncoding("utf-8");
            Part part = request.getPart("file");
            // 解析出原始文件名
            // 获取指定的头部属性
            String header = part.getHeader("Content-Disposition");
            int index = header.lastIndexOf("=");
            String fileName = header.substring(index + 2, header.length() - 1);
            // 完成文件上传
            part.write(path + fileName);
        }
    
    }
    

springmvc实现

上传(方式一)

  • //@RequestParam("file")将name-file控件得到的文件封装成CommonsNultipartFile对象
        //批量上传CommonsMuLtipartFiLe则为数组即可
        @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";
            }
    
            //上传路径保存设置
            String path = request.getServletContext( ).getRealPath("/upload");
            //如果路径不存在,创建一个
            File realPath = new File(path);
            if (!realPath.exists()){
                realPath. mkdir();
            }
    
            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";
        } 
    

上传(方式二)

  •  /*
     * 采用file.Transto 来保存上传的文件
    */
    @RequestMapping("fileUpload2")
    public String  fileUpload2(@RequestParam("file") CommonsMultipartFile file,HttpServletRequest request) throws IOException {
        //获取文件名
        String fileName = file.getOriginalFilename();
        //生成随机编号(避免文件名相同)
        UUID uuid = UUID.randomUUID();
        String path=request.getServletContext().getRealPath("/file")+"\\"+uuid+fileName;
        System.out.println(path);
        File newFile = new File(path);
        
        //通过CommonsMultipartFile的方法直接写文件(注意这个时候)
        file.transferTo(newFile);
        return "forward:/index.jsp";
    }
    

下载

  • @RequestMapping(value="/download")
        public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
            //要下载的图片地址
            String path = request.getServletContext().getRealPath("/web");
            String fileName ="桌面.PNG" ;
    
            //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 null;
        }
    

邮件的发送

在网络上实现邮件功能,必须要有专门的邮件服务器。这些邮件服务器类似于现实生活中的邮局,它主要负责接收用户投递过来的邮件,并把邮件投递到邮件接收者的电子邮箱中。

SMTP服务器地址:一般是 smtp.xxx.com,比如qq邮箱是smtp.qq.com。

SMTP协议:通常把处理用户smtp请求(邮件发送请求)的服务器称之为SMTP服务器(邮件发送服务器)。

POP3协议:通常把处理用户pop3请求(邮件接收请求)的服务器称之为POP3服务器(邮件接收服务器)。

img

  1. 导包
<!-- 邮件 -->
<dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.5.0-b01</version>
</dependency>

普通邮件发送

public class test {


        public static void main(String[] args) throws MessagingException, GeneralSecurityException {
            //创建一个配置文件并保存
            Properties properties = new Properties();

            properties.setProperty("mail.host","smtp.qq.com");

            properties.setProperty("mail.transport.protocol","smtp");

            properties.setProperty("mail.smtp.auth","true");


            //QQ存在一个特性设置SSL加密
            MailSSLSocketFactory sf = new MailSSLSocketFactory();
            sf.setTrustAllHosts(true);
            properties.put("mail.smtp.ssl.enable", "true");
            properties.put("mail.smtp.ssl.socketFactory", sf);

            //创建一个session对象
            Session session = Session.getDefaultInstance(properties, new Authenticator() {
                @Override
                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication("1423457753@qq.com","授权码");
                }
            });

            //开启debug模式
            session.setDebug(true);

            //获取连接对象
            Transport transport = session.getTransport();

            //连接服务器
            transport.connect("smtp.qq.com","1423457753@qq.com","16位授权码");

            //创建邮件对象
            MimeMessage mimeMessage = new MimeMessage(session);

            //邮件发送人
            mimeMessage.setFrom(new InternetAddress("1423457753@qq.com"));

            //邮件接收人
            mimeMessage.setRecipient(Message.RecipientType.TO,new InternetAddress("1423457753@qq.com"));

            //邮件标题
            mimeMessage.setSubject("Hello world");

            //邮件内容
            mimeMessage.setContent("System.out.print","text/html;charset=UTF-8");

            //发送邮件
            transport.sendMessage(mimeMessage,mimeMessage.getAllRecipients());

            //关闭连接
            transport.close();
        }


}

复杂的邮件

MIME(多用途互联网邮件扩展类型)

MimeBodyPart类

javax.mail.internet.MimeBodyPart类 表示的是一个MIME消息,它和MimeMessage类一样都是从Part接口继承过来。

MimeMultipart类

javax.mail.internet.MimeMultipart是抽象类 Multipart的实现子类,它用来组合多个MIME消息。一个MimeMultipart对象可以包含多个代表MIME消息的MimeBodyPart对象

在这里插入图片描述

public class test {

    public static void main(String[] args) throws GeneralSecurityException, MessagingException {
        Properties prop = new Properties();
        prop.setProperty("mail.host", "smtp.qq.com"); // 设置QQ邮件服务器
        prop.setProperty("mail.transport.protocol", "smtp"); // 邮件发送协议
        prop.setProperty("mail.smtp.auth", "true"); // 需要验证用户名密码

        // QQ邮箱设置SSL加密
        MailSSLSocketFactory sf = new MailSSLSocketFactory();
        sf.setTrustAllHosts(true);
        prop.put("mail.smtp.ssl.enable", "true");
        prop.put("mail.smtp.ssl.socketFactory", sf);

        //1、创建定义整个应用程序所需的环境信息的 Session 对象
        Session session = Session.getDefaultInstance(prop, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                //传入发件人的姓名和授权码
                return new PasswordAuthentication("1423457753@qq.com","tvqczbqkyrfabbeh");
            }
        });

        //2、通过session获取transport对象
        Transport transport = session.getTransport();

        //3、通过transport对象邮箱用户名和授权码连接邮箱服务器
        transport.connect("smtp.qq.com","1423457753@qq.com","tvqczbqkyrfabbeh");

        //4、创建邮件,传入session对象
        MimeMessage mimeMessage = complexEmail(session);

        //5、发送邮件
        transport.sendMessage(mimeMessage,mimeMessage.getAllRecipients());

        //6、关闭连接
        transport.close();

    }

    public static MimeMessage complexEmail(Session session) throws MessagingException {
        //消息的固定信息
        MimeMessage mimeMessage = new MimeMessage(session);

        //发件人
        mimeMessage.setFrom(new InternetAddress("1423457753@qq.com"));
        //收件人
        mimeMessage.setRecipient(Message.RecipientType.TO,new InternetAddress("1423457753@qq.com"));
        //邮件标题
        mimeMessage.setSubject("带图片和附件的邮件");

        //邮件内容
        //准备图片数据
        MimeBodyPart image = new MimeBodyPart();
        DataHandler handler = new DataHandler(new FileDataSource("D:\\电脑备份\\桌面.png"));
        image.setDataHandler(handler);
        image.setContentID("photo.png"); //设置图片id

        //准备文本
        MimeBodyPart text = new MimeBodyPart();
        text.setContent("一段文字中插入图片<img src='cid:photo.png'>下一段文字", "text/html;charset=utf-8");

        //附件
        MimeBodyPart appendix = new MimeBodyPart();
        appendix.setDataHandler(new DataHandler(new FileDataSource("D:\\电脑备份\\settings.xml")));
        appendix.setFileName("settings.xml");

        //拼装邮件正文
        MimeMultipart mimeMultipart = new MimeMultipart();
        mimeMultipart.addBodyPart(image);
        mimeMultipart.addBodyPart(text);
        mimeMultipart.setSubType("related");//文本和图片内嵌成功

        //将拼装好的正文内容设置为主体
        MimeBodyPart contentText = new MimeBodyPart();
        contentText.setContent(mimeMultipart);

        //拼接附件
        MimeMultipart allFile = new MimeMultipart();
        allFile.addBodyPart(appendix);//附件
        allFile.addBodyPart(contentText);//正文
        allFile.setSubType("mixed"); //正文和附件都存在邮件中,所有类型设置为mixed

        //放到Message消息中
        mimeMessage.setContent(allFile);
        mimeMessage.saveChanges();//保存修改

        return mimeMessage;
    }

}

标签:return,String,SpringMVC,eNo,ModelAndView,new,public
来源: https://blog.csdn.net/Always_moving/article/details/115816531

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有