4-SpringMVC

文章目录

  • 项目源码地址
  • 回顾-MVC
    • 什么是MVC?
    • MVC各部分组成
  • 回顾-Servlet
    • Maven创建Web项目
      • 1、创建Maven父工程pom,并导入依赖
      • 2、用Maven新建一个Web Module
      • 3、代码:HelloServlet.java
      • 3、代码-hello.jsp
      • 3、代码-web.xml
      • 4、配置Tomcat
      • 5、浏览器测试
    • Maven创建jar项目,并手动添加web依赖
  • 初识SpringMVC
    • SpringMVC的基础知识
    • DispatcherServlet:中心控制器
    • SpringMVC执行原理
  • 第一个SpringMVC程序
    • xml配置实现
      • 1、在上述父工程下,创建一个Web Module
      • 2、配置web.xml,注册DispatchServlet
      • 3、编写Spring MVC的配置文件【不同】
      • 4、编写操作业务Controller【不同】
      • 5、编写要跳转的jsp页面
      • 6、启动测试
    • annotation注解实现
      • 1、在上述父工程下,创建一个Web Module
      • 2、配置web.xml,注册DispatchServlet
      • 3、编写Spring MVC的配置文件【不同】
      • 4、编写操作业务Controller【不同】
      • 5、编写要跳转的jsp页面
      • 6、启动测试
  • 控制器:Controller
    • 控制器的作用
    • 控制器实现
      • 项目Module名称
      • 实现--接口定义
      • 实现--注解实现
      • 总结
    • 注解:@RequestMapping
      • 作用
      • 示例
  • RestFul风格
    • 什么是RestFul?
      • RestFul
      • 资源和资源操作
      • 资源操作方法对比
    • 示例
      • 代码
      • 应用:@PathVariable
      • 应用:method属性
      • 应用:@GetMapping、......
  • 数据处理及跳转
    • 项目Module名称
    • 结果跳转
      • ModelAndView
      • ServletAPI
      • SpringMVC-无需视图解析器
      • SpringMVC-有视图解析器
    • 数据处理-提交到后端的数据
    • 数据处理-数据显示到前端
    • 乱码处理
      • 方法1-springMVC-过滤器
      • 方法2-Tomcat修改配置文件
      • 方法3-自定义过滤器
      • 总结
  • Json
    • 项目Module名称
    • 什么是Json?
      • 概念
      • 语法格式
      • Json和JavaScript的区别
      • Json和JavaScript的相互转换
    • Controller返回Json数据:jackson
      • Module准备
      • Controller核心代码
      • 统一处理乱码问题
    • Controller返回Json数据:fastjson
      • Module准备
      • fastjson三大核心类
      • 数据类型相互转换
  • Ajax
  • 拦截器:Interceptor
    • 什么是拦截器?
      • 概念
      • 过滤器和拦截器的区别
    • 拦截器使用
  • 文件上传和下载
    • Module准备
    • 核心代码展示
      • 前端页面
      • Controller

项目源码地址

GitHubhttps://github.com/Web-Learn-GSF/Java_Learn_Examples
父工程Java_Framework_SpringMVC

回顾-MVC

什么是MVC?

MVC是(Model、View、Controller的缩写)一种软件设计规范,将业务逻辑、数据、显示三者分离开来组织代码

MVC主要作用是降低了视图与业务逻辑间的双向耦合

MVC各部分组成

模块组成
Model(模型)提供要展示的数据,可以认为是领域模型或JavaBean组件(包含数据和行为)
View(视图)负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西
Controller(控制器)接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。也就是说控制器做了个调度员的工作

回顾-Servlet

这一章将讲述两种创建Web项目的方法来回顾servlet:

  • Maven创建web项目,运行servlet

  • Maven创建jar项目,手动添加框架依赖,运行servlet**(还没调试通顺,后续有空继续整)**

同时也将讲述Tomcat9和Tomcat10在servlet包依赖上的不同

Maven创建Web项目

1、创建Maven父工程pom,并导入依赖

  • 若Tomcat版本为10,依赖导入
<dependencies>
    <!-- 没有争议的依赖 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.1</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>6.0.9</version>
    </dependency>

    <!-- 有版本争议的依赖:servlet、jsp-->
    <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-servlet-api -->
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-servlet-api</artifactId>
      <version>10.0.4</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jsp-api -->
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-jsp-api</artifactId>
      <version>10.0.4</version>
    </dependency>
  </dependencies>
  • 若Tomcat版本为9,依赖导入
<dependencies>
    <!-- 没有争议的依赖 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.1</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>6.0.9</version>
    </dependency>

    <!-- 有版本争议的依赖:servlet、jsp-->
   <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>servlet-api</artifactId>
       <version>2.5</version>
   </dependency>
   <dependency>
       <groupId>javax.servlet.jsp</groupId>
       <artifactId>jsp-api</artifactId>
       <version>2.2</version>
   </dependency>
   <dependency>
       <groupId>javax.servlet</groupId>
       <artifactId>jstl</artifactId>
       <version>1.2</version>
   </dependency>
</dependencies>

Tomcat9及以前,servlet依赖包名是 javax.servlet;Tomcat10之后,servlet依赖包名是 jakarta.servlet

如若不注意版本匹配,启动Tomcat会爆出404问题

2、用Maven新建一个Web Module

Module名字:Demo-01-ServletReview-MavenWebCreate

Module内容解释:

  • pom文件里面的packaging标签是war

整体结构及后续代码

  • Maven创建的web项目,webapp在main目录下,跟手动添加web依赖所在的目录不一样

image-20231130172457456

3、代码:HelloServlet.java

Tomcat版本为10的代码

package GSF.Example.Servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //取得参数
        String method = req.getParameter("method");
        if ("add".equals(method)){
            req.getSession().setAttribute("msg","执行了add方法");
        }
        if ("delete".equals(method)){
            req.getSession().setAttribute("msg","执行了delete方法");
        }
        //业务逻辑:暂无

        //视图跳转
        req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

Tomcat版本为9的代码

package GSF.Example.Servlet;

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 HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //取得参数
        String method = req.getParameter("method");
        if ("add".equals(method)){
            req.getSession().setAttribute("msg","执行了add方法");
        }
        if ("delete".equals(method)){
            req.getSession().setAttribute("msg","执行了delete方法");
        }
        //业务逻辑:暂无

        //视图跳转
        req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

区别:包的名字

  • Tomcat10:jakarta.servlet
  • Tomcat9:javax.servlet

3、代码-hello.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
   <title>Kuangshen</title>
</head>
<body>
${msg}
</body>
</html>
  • web2.4之后,默认禁止el表达式,即${}不会从session域中获取数据
  • 通过添加上边的第二行代码:<%@ page isELIgnored="false" %>,可以关闭对el表达式的禁止,实现从session域中获取数据

3、代码-web.xml

Maven创建web项目,默认的web.xml文件内容

  • 头文件不太对劲,但是能用
  • 有空再探讨具体有啥区别
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>GSF.Example.Servlet.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/user</url-pattern>
  </servlet-mapping>

</web-app>

若是手动添加框架依赖,创建的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
        version="4.0">
  
  <servlet>
    <servlet-name>HelloServlet</servlet-name>
    <servlet-class>GSF.Example.Servlet.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloServlet</servlet-name>
    <url-pattern>/user</url-pattern>
  </servlet-mapping>

</web-app>

4、配置Tomcat

image-20231130175322983

image-20231130175420492

image-20231130175521737

image-20231130175558908

image-20231130175709773

  • 暂不清楚为啥要选这个,也不知道选不带有war exploded的会有啥问题

image-20231130175900950

5、浏览器测试

  • localhost:8080/user?method=add
  • localhost:8080/user?method=delete

Maven创建jar项目,并手动添加web依赖

暂时没调试通顺

初识SpringMVC

SpringMVC的基础知识

Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架

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

Spring MVC特点

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

Spring的web框架围绕DispatcherServlet [ 调度Servlet ] 设计。

DispatcherServlet的作用是将请求分发到不同的处理器。从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解形式进行开发,十分简洁。

DispatcherServlet:中心控制器

Spring的web框架围绕DispatcherServlet设计:

  • DispatcherServlet的作用是将请求分发到不同的处理器
  • 从Spring 2.5开始,使用Java 5或者以上版本的用户可以采用基于注解的controller声明方式

Spring MVC框架像许多其他MVC框架一样, 以请求为驱动 , 围绕一个中心Servlet分派请求及提供其他功能,DispatcherServlet是一个实际的Servlet (它继承自HttpServlet 基类)

SpringMVC执行原理

image-20231210103958973

实现部分:表示框架已经帮忙完成;虚线部分:表示需要我们手动编写的地方

步骤1:

  • DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求
  • 假设请求的url为 : localhost:8080/SpringMVC/hello
  • web.xml中定义,拦截所有请求
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
    <!--启动级别-1-->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!--/ 匹配所有的请求;(不包括.jsp)-->
  <!--/* 匹配所有的请求;(包括.jsp)-->
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

步骤2:

  • HandlerMapping为处理器映射,被DispatcherServlet调用
  • HandlerMapping根据请求url查找Handler
  • springmvc-servlet.xml中注册HandlerMapping的bean
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

步骤3:

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

步骤4:

  • HandlerExecution将解析后的信息传递给DispatcherServlet
  • 解析后的信息:处理器对象及处理器拦截器

步骤5:

  • HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler
  • springmvc-servlet.xml中注册HandlerAdapter的bean
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

步骤6:

  • Handler让具体的Controller执行
  • springmvc-servlet.xml中注册Handler的bean
<bean id="/hello" class="GSF.Example.Controller.HelloController"/>

步骤7:

  • Controller将具体的执行信息返回给HandlerAdapter
  • 返回的信息如:ModelAndView

步骤8:

  • HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet

步骤9:

  • DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名
  • springmvc-servlet.xml中注册bean,并完成相关配置
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
    <!--前缀-->
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <!--后缀-->
    <property name="suffix" value=".jsp"/>
</bean>

步骤10:

  • 视图解析器将解析的逻辑视图名传给DispatcherServlet

步骤11:

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

步骤12:

  • 最终视图呈现给用户

第一个SpringMVC程序

xml配置实现

1、在上述父工程下,创建一个Web Module

Module名字:Demo-02-SpringMVC-xml

整体结构图及后续写入代码

image-20231130203829024

2、配置web.xml,注册DispatchServlet

  • web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!--1.注册DispatcherServlet-->
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--关联一个springmvc的配置文件:【servlet-name】-servlet.xml-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
    <!--启动级别-1-->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!--/ 匹配所有的请求;(不包括.jsp)-->
  <!--/* 匹配所有的请求;(包括.jsp)-->
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

3、编写Spring MVC的配置文件【不同】

  • springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>

    <!--视图解析器:DispatcherServlet给他的ModelAndView-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver">
        <!--前缀-->
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <!--后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>


    <!--Handler-->
    <bean id="/hello" class="GSF.Example.Controller.HelloController"/>

</beans>

4、编写操作业务Controller【不同】

  • HelloController.java
package GSF.Example.Controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

//注意:这里我们先导入Controller接口
public class HelloController implements Controller {

    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //ModelAndView 模型和视图
        ModelAndView mv = new ModelAndView();
        //封装对象,放在ModelAndView中。Model
        mv.addObject("msg","HelloSpringMVC!");
        //封装要跳转的视图,放在ModelAndView中
        mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp
        return mv;
    }
}
  • 在springmvc-servlet.xml中注册该实现类的bean

5、编写要跳转的jsp页面

  • hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
    <title>Kuangshen</title>
</head>
<body>
${msg}
</body>
</html>

6、启动测试

  • localhost:8080/hello

annotation注解实现

1、在上述父工程下,创建一个Web Module

Module名称:Demo-02-SpringMVC-annotation

整体结构图及后续写入代码

image-20231130225354825

2、配置web.xml,注册DispatchServlet

  • web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

  <!--1.注册servlet-->
  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--通过初始化参数指定SpringMVC配置文件的位置,进行关联-->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc-servlet.xml</param-value>
    </init-param>
    <!-- 启动顺序,数字越小,启动越早 -->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <!--所有请求都会被springmvc拦截 -->
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

3、编写Spring MVC的配置文件【不同】

  • springmvc-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 -->
    <context:component-scan base-package="GSF.Example.Controller"/>
    <!-- 让Spring MVC不处理静态资源 -->
    <mvc:default-servlet-handler />
    <!--
    支持mvc注解驱动
        在spring中一般采用@RequestMapping注解来完成映射关系
        要想使@RequestMapping注解生效
        必须向上下文中注册DefaultAnnotationHandlerMapping
        和一个AnnotationMethodHandlerAdapter实例
        这两个实例分别在类级别和方法级别处理。
        而annotation-driven配置帮助我们自动完成上述两个实例的注入。
     -->
    <mvc:annotation-driven />

    <!-- 视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          id="internalResourceViewResolver">
        <!-- 前缀 -->
        <property name="prefix" value="/WEB-INF/jsp/" />
        <!-- 后缀 -->
        <property name="suffix" value=".jsp" />
    </bean>

</beans>

4、编写操作业务Controller【不同】

package GSF.Example.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/HelloController")
public class HelloController {

    //真实访问地址 : 项目名/HelloController/hello
    @RequestMapping("/hello")
    public String sayHello(Model model){
        //向模型中添加属性msg与值,可以在JSP页面中取出并渲染
        model.addAttribute("msg","hello, SpringMVC");
        //web-inf/jsp/hello.jsp
        return "hello";
    }
}
  • 通过注解扫描,实现自动注入bean

5、编写要跳转的jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ page isELIgnored="false" %>
<html>
<head>
    <title>你好</title>
</head>
<body>
${msg}
</body>
</html>

6、启动测试

  • localhost:8080/HelloController/hello

控制器:Controller

控制器的作用

控制器复杂提供访问应用程序的行为,通常通过接口定义注解定义两种方法实现。

控制器负责解析用户的请求并将其转换为一个模型。

在Spring MVC中一个控制器类可以包含多个方法

在Spring MVC中,对于Controller的配置方式有很多种

控制器实现

项目Module名称

Demo-03-SpringMVC-Controller_Restful

实现–接口定义

package GSF.Example.Controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.ui.Model;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;


public class HelloController_Interface implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ModelAndView mv = new ModelAndView();
        mv.addObject("msg", "hello, SpringMVC, Controller_Interface");
        mv.setViewName("hello");
        return mv;
    }
}

实现–注解实现

package GSF.Example.Controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;


@Controller
@RequestMapping("/controller")
public class HelloController_Annotation {

    //真实访问地址 : 项目名/controller/hello
    @RequestMapping("/annotation")
    public String sayHello(Model model){
        //向模型中添加属性msg与值,可以在JSP页面中取出并渲染
        model.addAttribute("msg","hello,SpringMVC, Controller_Annotation");
        //web-inf/jsp/hello.jsp
        return "hello";
    }
}

总结

注解开发会更频繁,且高效

两个方法的跳转指向同一个jsp页面,视图复用,可以看出控制器和视图之间是弱耦合关系

注解:@RequestMapping

作用

用于映射url到控制器类或一个特定的处理程序方法

可用于类或方法上:

  • 用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径
  • 用于方法上,表示可以通过该路径,访问到该方法

示例

// 仅注解在方法上:localhost:8080 / 项目名 / h1

@Controller
public class TestController {
   @RequestMapping("/h1")
   public String test(){
       return "test";
  }
}
// 既注解在类上,也注解在方法上:localhost:8080 /项目名/ admin / h1

@Controller
@RequestMapping("/admin")
public class TestController {
   @RequestMapping("/h1")
   public String test(){
       return "test";
  }
}

RestFul风格

什么是RestFul?

RestFul

Restful就是一个资源定位及资源操作的风格,不是标准也不是协议,只是一种风格

基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制

资源和资源操作

  • 资源:互联网所有的事物都可以被抽象为资源
  • 资源操作:
    • 使用POST、DELETE、PUT、GET对资源进行操作
    • 分别对应对资源的增、删、改、查(查单一、查全部)操作

资源操作方法对比

操作Restful传统
http://127.0.0.1/item,POST方法http://127.0.0.1/item/saveItem.action,POST方法
http://127.0.0.1/item/1,DELETE方法http://127.0.0.1/item/deleteItem.action?id=1,GET方法或POST方法
http://127.0.0.1/item,PUT方法http://127.0.0.1/item/updateItem.action,POST方法
查(单一)http://127.0.0.1/item/,GET方法(不带参数)http://127.0.0.1/item/queryItem.action?id=1,GET方法
查(全部)http://127.0.0.1/item/1/,GET方法(带参数)http://127.0.0.1/item/queryItem.action/all,GET方法

示例

代码

  • test1
package GSF.Example.Restful;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class Restful {
    @RequestMapping("/restful/{var1}/{var2}")
    public String calculate(@PathVariable int var1, @PathVariable int var2, Model model){
        int result = var1 + var2;
        model.addAttribute("msg", "求和结果:" + result);
        return "hello";
    }
}
  • test2
package GSF.Example.Restful;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class Restful_method {
    //@RequestMapping(value = "/restful_method/{var1}/{var2}", method = {RequestMethod.POST})
    @RequestMapping(value = "/restful_method/{var1}/{var2}")
    @GetMapping
    public String calculate(@PathVariable int var1, @PathVariable int var2, Model model){
        int result = var1 + var2;
        model.addAttribute("msg", "求和结果:" + result);
        return "hello";
    }
}

应用:@PathVariable

  • 将url变量绑定到方法参数上

  • 若url变量传入的类型和方法参数的类型不对应,会出现404无法访问,而不是在程序中出现类型不匹配异常

应用:method属性

  • 指定该url的请求方法

应用:@GetMapping、…

  • 通过注解的形式,指定url的请求方法类型

  • @GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping

数据处理及跳转

项目Module名称

Demo-04-SpringMVC-DataProcess_Redirection

  • 代码参考:上述连接
  • 该部分,文章中不贴入完整代码

结果跳转

ModelAndView

package GSF.Example.ResultRedirection;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.mvc.Controller;

public class ModelAndView implements Controller {
    @Override
    public org.springframework.web.servlet.ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        org.springframework.web.servlet.ModelAndView mv = new org.springframework.web.servlet.ModelAndView();
        mv.addObject("msg", "hello, Result Redirection, ModelAndView");
        mv.setViewName("hello");
        return mv;
    }
}
  • springmvc-servlet中注册bean

  • addObject:写入数据

  • setViewName:设置要跳转的视图资源

    • 配合视图解析器

ServletAPI

package GSF.Example.ResultRedirection;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;

@Controller
public class ServletAPI {

    @RequestMapping("servlet_redirection/test1")
    public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
        // 输出
        rsp.getWriter().println("hello, Result Redirection, ServletAPI: rsp.getWriter().println");
    }

    @RequestMapping("servlet_redirection/test2")
    // 重定向:禁止指向受保护的视图资源
    public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
        rsp.sendRedirect("/Result_Redirection/test2.jsp");
    }

    @RequestMapping("servlet_redirection/test3")
    public void test3(HttpServletRequest req, HttpServletResponse rsp) throws IOException, ServletException {
        // 请求转发:可以指向受保护的视图资源
        req.setAttribute("msg", "hello, Result Redirection, ServletAPI: req.setAttribute, req.getRequestDispatcher");
        req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req, rsp);
    }
}
  • 注意:该代码针对Tomcat10,servlet包名前缀是“jakarta”

  • test1:直接在响应结果中写入数据,支持html标签

  • test2:响应重定向,重新请求资源(禁止请求受保护资源)

  • test3:请求转发,请求和响应信息可以继续传递(可以请求受保护资源)

SpringMVC-无需视图解析器

  • 需要写全路径
package GSF.Example.ResultRedirection;

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

// 请求前需要先注释掉springmvc-servlet.xml的视图解析器

@Controller
public class SpringMVC_NoViewParser {

    @RequestMapping("/springMvc_redirection/test1")
    public String test1() {
        // 转发
        return "/index_1.jsp";
    }

    @RequestMapping("/springMvc_redirection/test2")
    public String test2() {
        // 转发
        //return "forward:/index.jsp";
        //return "forward:/index_1.jsp";
        return "forward:/WEB-INF/jsp/hello.jsp";
    }

    @RequestMapping("/springMvc_redirection/test3")
    public String test3() {
        // 重定向:不让定向到受保护的视图资源内
        //return "redirect:/index.jsp";
        return "redirect:/WEB-INF/jsp/hello.jsp";
    }
}

SpringMVC-有视图解析器

  • 根据视图解析器的前缀和后缀,补全剩余路径即可
  • 针对响应重定向,不受视图解析器的影响,写入全路径即可
package GSF.Example.ResultRedirection;

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

import java.io.IOException;

@Controller
public class SpringMVC_ViewParser {
    @RequestMapping("/springMvc_redirection_VP/test1")
    public String test1() throws IOException {
        // 转发:自动借助视图解析器补充前缀和后缀
        // return "index_1";     // 不行
        // return "/index_2";    // 行
        return "/jsp/hello";    // 行
    }

    @RequestMapping("/springMvc_redirection_VP/test2")
    public String test2() throws IOException {
        // 重定向:不需要视图解析器,写全路径
        return "redirect:/Result_Redirection/test2.jsp";
    }
}

数据处理-提交到后端的数据

package GSF.Example.DataProcess;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/data_process")
public class ProcessSubmitData {
    @RequestMapping("/same_name")
    public String test1(String name){
        System.out.println(name);
        return "/jsp/hello";
    }

    @RequestMapping("/different_name")
    public String test2(@RequestParam("username") String name){
        System.out.println(name);
        return "/jsp/hello";
    }

    @RequestMapping("/object")
    public String test3(User user){
        System.out.println(user);
        return "/jsp/hello";
    }
}
  • test1:localhost:8080/data_process/same_name?name=123456
  • test2:localhost:8080/data_process/different_name?username=123456
  • test3:localhost:8080/data_process/object?name=gsf&id=1&age=15

数据处理-数据显示到前端

package GSF.Example.DataShow;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class ShowDataToView {

    // 第一种:ModelAndView,参考ResultRedirection/ModelAndView

    // ModelMap
    @RequestMapping("/show_data")
    public String test1(@RequestParam("username") String name, ModelMap model){
        //封装要显示到视图中的数据
        //相当于req.setAttribute("name",name);
        model.addAttribute("msg",name);
        System.out.println(name);
        return "/jsp/hello";
    }

    // Model
    @RequestMapping("/show_data_2")
    public String test2(@RequestParam("username") String name, Model model){
        //封装要显示到视图中的数据
        //相当于req.setAttribute("name",name);
        model.addAttribute("msg",name);
        System.out.println(name);
        return "/jsp/hello";
    }
}
  • test1:ModelMap
  • test2:Model

乱码处理

方法1-springMVC-过滤器

  • 使用springMVC提供的过滤器,在web.xml中配置
<filter>
   <filter-name>encoding</filter-name>
   <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
   <init-param>
       <param-name>encoding</param-name>
       <param-value>utf-8</param-value>
   </init-param>
</filter>
<filter-mapping>
   <filter-name>encoding</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>
  • 极端情况下,对get支持不好

方法2-Tomcat修改配置文件

<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
          connectionTimeout="20000"
          redirectPort="8443" />

方法3-自定义过滤器

  • 过滤器
package com.kuang.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
* 解决get和post请求 全部乱码的过滤器
*/
public class GenericEncodingFilter implements Filter {

   @Override
   public void destroy() {
  }

   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
       //处理response的字符编码
       HttpServletResponse myResponse=(HttpServletResponse) response;
       myResponse.setContentType("text/html;charset=UTF-8");

       // 转型为与协议相关对象
       HttpServletRequest httpServletRequest = (HttpServletRequest) request;
       // 对request包装增强
       HttpServletRequest myrequest = new MyRequest(httpServletRequest);
       chain.doFilter(myrequest, response);
  }

   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
  }

}
  • 过滤器中调用的方法
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {

   private HttpServletRequest request;
   //是否编码的标记
   private boolean hasEncode;
   //定义一个可以传入HttpServletRequest对象的构造函数,以便对其进行装饰
   public MyRequest(HttpServletRequest request) {
       super(request);// super必须写
       this.request = request;
  }

   // 对需要增强方法 进行覆盖
   @Override
   public Map getParameterMap() {
       // 先获得请求方式
       String method = request.getMethod();
       if (method.equalsIgnoreCase("post")) {
           // post请求
           try {
               // 处理post乱码
               request.setCharacterEncoding("utf-8");
               return request.getParameterMap();
          } catch (UnsupportedEncodingException e) {
               e.printStackTrace();
          }
      } else if (method.equalsIgnoreCase("get")) {
           // get请求
           Map<String, String[]> parameterMap = request.getParameterMap();
           if (!hasEncode) { // 确保get手动编码逻辑只运行一次
               for (String parameterName : parameterMap.keySet()) {
                   String[] values = parameterMap.get(parameterName);
                   if (values != null) {
                       for (int i = 0; i < values.length; i++) {
                           try {
                               // 处理get乱码
                               values[i] = new String(values[i]
                                      .getBytes("ISO-8859-1"), "utf-8");
                          } catch (UnsupportedEncodingException e) {
                               e.printStackTrace();
                          }
                      }
                  }
              }
               hasEncode = true;
          }
           return parameterMap;
      }
       return super.getParameterMap();
  }

   //取一个值
   @Override
   public String getParameter(String name) {
       Map<String, String[]> parameterMap = getParameterMap();
       String[] values = parameterMap.get(name);
       if (values == null) {
           return null;
      }
       return values[0]; // 取回参数的第一个值
  }

   //取所有值
   @Override
   public String[] getParameterValues(String name) {
       Map<String, String[]> parameterMap = getParameterMap();
       String[] values = parameterMap.get(name);
       return values;
  }
}

总结

  • 为了避免乱码问题,在可能设置编码的地方,都设置为UTF-8
  • springMVC提供的过滤器,基本就够用了

Json

项目Module名称

Demo-05-SpringMVC-Json

  • 代码参考:上述连接
  • 该部分,文章中不贴入完整代码

什么是Json?

概念

  • JSON(JavaScript Object Notation, JS 对象标记)是一种轻量级的数据交换格式,目前使用特别广泛。
  • 采用完全独立于编程语言的文本格式来存储和表示数据。
  • 简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。
  • 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

语法格式

  • 对象表示为键值对,数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组

Json和JavaScript的区别

JSON 是 JavaScript 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串

var obj = {a: 'Hello', b: 'World'}; //这是一个对象,注意键名也是可以使用引号包裹的
var json = '{"a": "Hello", "b": "World"}'; //这是一个 JSON 字符串,本质是一个字符串

Json和JavaScript的相互转换

var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//结果是 {a: 'Hello', b: 'World'}

var json = JSON.stringify({a: 'Hello', b: 'World'});
//结果是 '{"a": "Hello", "b": "World"}'

Controller返回Json数据:jackson

Module准备

1、导包

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.9.8</version>
</dependency>

2、建立Module,完成springmvc-servlet.xml、web.xml配置(大差不差,不再详细贴出代码)

Controller核心代码

package GSF.Example.Controller;

import GSF.Example.Pojo.User;
import GSF.Example.Utils.JsonUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

//@Controller	// 使用Controller,需要在方法上添加@ResponseBody注解,保证返回json形式数据
@RestController // 使用RestController,保证返回的都是json形式数据
public class UserController {

    @RequestMapping("/json1")
    //@RequestMapping(value = "/json1",produces = "application/json;charset=utf-8")	// 设置返回数据字符集,避免乱码
    //@ResponseBody
    public String json1() throws JsonProcessingException {
        //创建一个jackson的对象映射器,用来解析数据
        ObjectMapper mapper = new ObjectMapper();
        //创建一个对象
        User user = new User("秦疆1号", 3, "男");
        //将我们的对象解析成为json格式
        String str = mapper.writeValueAsString(user);
        System.out.println(str);
        //由于@ResponseBody注解,这里会将str转成json格式返回;十分方便
        return str;
    }

    @RequestMapping("/json2")
    public String json2() throws JsonProcessingException {
        //创建一个jackson的对象映射器,用来解析数据
        ObjectMapper mapper = new ObjectMapper();
        //创建一个对象
        User user1 = new User("秦疆1号", 3, "男");
        User user2 = new User("秦疆2号", 3, "男");
        User user3 = new User("秦疆3号", 3, "男");
        User user4 = new User("秦疆4号", 3, "男");
        List<User> list = new ArrayList<User>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        list.add(user4);

        //将我们的对象解析成为json格式
        String str = mapper.writeValueAsString(list);
        return str;
    }

    // 默认返回一个时间戳,是一个lang整数值
    @RequestMapping("/json3")
    public String json3() throws JsonProcessingException {

        ObjectMapper mapper = new ObjectMapper();

        //创建时间一个对象,java.util.Date
        Date date = new Date();
        //将我们的对象解析成为json格式
        String str = mapper.writeValueAsString(date);
        return str;
    }

    // 通过定义返回时间的格式返回数据
    @RequestMapping("/json4")
    public String json4() throws JsonProcessingException {

        ObjectMapper mapper = new ObjectMapper();

        //不使用时间戳的方式
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        //自定义日期格式对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //指定日期格式
        mapper.setDateFormat(sdf);

        Date date = new Date();
        String str = mapper.writeValueAsString(date);

        return str;
    }

    @RequestMapping("/json5")
    public String json5() throws JsonProcessingException {
        Date date = new Date();
        String json = JsonUtils.getJson(date);  // 将代码抽出来,自定义一个工具类
        return json;
    }
}

统一处理乱码问题

  • springmvc-servlet.xml配置
<!--Jackson统一解决乱码问题-->
<mvc:annotation-driven>
    <mvc:message-converters register-defaults="true">
        <bean class="org.springframework.http.converter.StringHttpMessageConverter">
            <constructor-arg value="UTF-8"/>
        </bean>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="failOnEmptyBeans" value="false"/>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

Controller返回Json数据:fastjson

Module准备

1、导包

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.60</version>
</dependency>

2、建立Module,完成springmvc-servlet.xml、web.xml配置(大差不差,不再详细贴出代码)

fastjson三大核心类

核心类代表解释
JSONObject代表 json 对象JSONObject实现了Map接口,猜想 JSONObject底层操作是由Map实现的
JSONObject对应json对象,通过各种形式的get()方法可以获取json对象中的数据,也可利用诸如size(),isEmpty()等方法获取"键:值"对的个数和判断是否为空
其本质是通过实现Map接口并调用接口中的方法完成的
JSONArray代表 json 对象数组内部是有List接口中的方法来完成操作的
JSON代表 JSONObject和JSONArray的转化JSON类源码分析与使用
主要是实现json对象,json对象数组,javabean对象,json字符串之间的相互转化

数据类型相互转换

  • json对象,json对象数组,javabean对象,json字符串之间的相互转化
package GSF.Example.Controller;

import GSF.Example.Pojo.User;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;

import java.util.ArrayList;
import java.util.List;

public class FastJsonDemo {
    public static void main(String[] args) {
        //创建一个对象
        User user1 = new User("秦疆1号", 3, "男");
        User user2 = new User("秦疆2号", 3, "男");
        User user3 = new User("秦疆3号", 3, "男");
        User user4 = new User("秦疆4号", 3, "男");
        List<User> list = new ArrayList<User>();
        list.add(user1);
        list.add(user2);
        list.add(user3);
        list.add(user4);
        
        System.out.println("*******Java对象 转 JSON字符串*******");
        String str1 = JSON.toJSONString(list);
        System.out.println("JSON.toJSONString(list)==>"+str1);
        String str2 = JSON.toJSONString(user1);
        System.out.println("JSON.toJSONString(user1)==>"+str2);

        System.out.println("\n****** JSON字符串 转 Java对象*******");
        User jp_user1=JSON.parseObject(str2,User.class);
        System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);

        System.out.println("\n****** Java对象 转 JSON对象 ******");
        JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
        System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));

        System.out.println("\n****** JSON对象 转 Java对象 ******");
        User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
        System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
       
    }
}

Ajax

学一半,后边再说吧,有点学不明白

拦截器:Interceptor

什么是拦截器?

概念

SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能

过滤器和拦截器的区别

过滤器拦截器
servlet规范中的一部分,任何java web工程都可以使用拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
通过配置,可以对所有要访问的资源进行拦截是AOP思想的具体应用,只会拦截访问的控制器方法,如果访问的是jsp/html/css/image/js是不会进行拦截的

拦截器使用

  • java代码
package GSF.Example.Interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class MyInterceptor implements HandlerInterceptor {

    //在请求处理的方法之前执行
    //如果返回true执行下一个拦截器
    //如果返回false就不执行下一个拦截器
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("------------处理前------------");
        return true;
    }

    //在请求处理方法执行之后执行
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("------------处理后------------");
    }

    //在dispatcherServlet处理后执行,做清理工作.
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("------------清理------------");
    }
}
  • springmvc-servlet.xml配置
<!--关于拦截器的配置-->
<mvc:interceptors>
    <mvc:interceptor>
        <!--/** 包括路径及其子路径-->
        <!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
        <!--/admin/** 拦截的是/admin/下的所有-->
        <mvc:mapping path="/**"/>
        <!--bean配置的就是拦截器-->
        <bean class="GSF.Example.Interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

文件上传和下载

Module准备

1、建立相关Module

2、导包

<!--文件上传有关的第三方库-->
<dependency>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
   <version>1.3.3</version>
</dependency>

3、springmvc-servlet.xml配置bean!!

<!--文件上传配置-->
<bean id="multipartResolver"  class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>
  • 这个bean的名字必须叫这个,不能为其他的

核心代码展示

前端页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<h2>Hello World!</h2>

<h1>上传文件</h1>
<h2>上传单个文件,java原生代码实现</h2>
<form action="/upload" enctype="multipart/form-data" method="post">
    <input type="file" name="file"/>
    <input type="submit" value="upload">
</form>

<h2>上传单个文件,调file.TransferTo保存文件代码</h2>
<form action="/upload2" enctype="multipart/form-data" method="post">
    <input type="file" name="file"/>
    <input type="submit" value="upload">
</form>

<h2>上传多个文件(多个文件选择框实现),调file.TransferTo保存文件代码</h2>
<form action="/upload3" enctype="multipart/form-data" method="post">
    <input type="file" name="file"/>
    <input type="file" name="file"/>
    <input type="submit" value="upload">
</form>

<h2>上传多个文件(单个文件选择框实现),调file.TransferTo保存文件代码</h2>
<form action="/upload3" enctype="multipart/form-data" method="post">
    <input type="file" name="file" multiple/>
    <input type="submit" value="upload">
</form>
</body>

<h1>下载文件</h1>
<h2>java原生代码实现</h2>
<a href="/download">点击下载</a>
</html>

Controller

package GSF.Example.Controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Controller
public class FileController {
    @RequestMapping("/upload")
    public String fileUpload_onefile_manualsave(@RequestParam("file") MultipartFile file , HttpServletRequest request) throws IOException {

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

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

        //上传路径保存设置
        String path = request.getServletContext().getRealPath("/upload");
        System.out.println(path);

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

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

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

    /*
     * 采用file.Transto 来保存上传的文件
     */
    @RequestMapping("/upload2")
    public String  fileUpload2(@RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {

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

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

        return "redirect:/index.jsp";
    }

    @RequestMapping("/upload3") // 等价于 @RequestMapping(value = "/upload", method = RequestMethod.POST)
    public String fileUpload(HttpServletRequest req, @RequestParam("file") MultipartFile[] files) throws IOException {
        List<String> pathStrs = new ArrayList<String>();
        if(files.length > 0){
            //循环多次上传多个文件
            for (MultipartFile file : files) {
                if(!file.isEmpty()){
                    //上传路径保存设置
                    String path = req.getServletContext().getRealPath("/upload");
                    File realPath = new File(path);
                    if (!realPath.exists()){
                        realPath.mkdir();
                    }
                    //上传文件地址
                    System.out.println("上传文件保存地址:"+realPath);

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

    // 下载文件的步骤:
    // 1、设置response响应头
    // 2、读取文件:InputStream
    // 3、写出文件:OutputStream
    // 4、执行操作
    // 5、关闭流(先开的流后关)
    @RequestMapping(value="/download")
    public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
        //要下载的图片地址
        String  path = request.getServletContext().getRealPath("/upload");
        String  fileName = "基础语法.jpg";

        //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;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/235066.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

“快速排序:一种美丽的算法混沌”(1.hoare)

欢迎来到我的博客&#xff01;在今天的文章中&#xff0c;我将采用一种独特且直观的方式来探讨我们的主题&#xff1a;我会使用一幅图像来贯穿整篇文章的讲解。这幅精心设计的图表不仅是我们讨论的核心&#xff0c;也是一个视觉辅助工具&#xff0c;帮助你更深入地理解和掌握本…

GPIO的使用--USART串口通信--传感器控制数据

目录 一、串口通信 1、概念 2、原理图 3、使用步骤 &#xff08;1&#xff09;寻找串口位置 &#xff08;2&#xff09;确定引脚编号 &#xff08;3&#xff09;编写代码 4、实验结果 实验代码 main.c usart.c usart.h 一、串口通信 1、概念 串行接口是一种可以将…

订单系统的设计与海量数据处理实战

概述 订单系统可以说是整个电商系统中最重要的一个子系统&#xff0c;因此订单数据可以算作电商企业最重要的数据资产。订单系统从代码上来说可分为两部分&#xff1a;订单程序和历史订单处理程序。数据存储进行分库分表。 订单系统业务分析 对于一个合格的订单系统&#xf…

程-c1语言-数组------—维数组和二维数组

1. 数组------—维数组和二维数组 字符数组中只能存放字符或字符串&#xff0c;这句话对不对&#xff1f; 字符数组中只能存放字符或字符串&#xff0c;这句话对不对&#xff1f; 不对&#xff0c;字符数组实际上是存放字符编码的 不对 &#xff0c;字符数组实际上是存放字符…

2024 年勒索软件:预期影响、目标和格局变化

随着勒索软件持续增加&#xff0c;我们可以预期这些组织 将继续改进其攻击方式并进行更大规模的操作以获取更大的利润。 如果组织不采取更积极的安全策略&#xff0c;就会面临更高的风险。 以下是我们预计 2024 年勒索软件的情况。 2024 年&#xff0c;我们将看到更多大规模…

解码方法dp

1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 从左往右 5.返回值 dp[n-1] 6.处理边界问题以及初始化问题的技巧

OpenAI承认ChatGPT变懒惰,正在修复该问题

OpenAI旗下的官方ChatGPT账号在社交平台表示&#xff0c;已经收到了大量用户关于GPT-4变懒惰的反馈。 这是因为自11月11日以来&#xff0c;OpenAI就没有更新过该模型。当然这不是故意的&#xff0c;大模型的行为是不可预测的&#xff0c;正在研究修复该问题。 外界猜测&#x…

深入了解UDP协议:特点、应用场景及市面上常见软件案例

目录 引言 UDP的特点 UDP的应用场景 市面上使用UDP的软件案例 结论 引言 在计算机网络中&#xff0c;UDP&#xff08;User Datagram Protocol&#xff09;是一种面向无连接、无状态的传输层协议。与TCP相比&#xff0c;UDP具有独特的特点和适用场景。本文将深入探讨UDP协…

Spring Cloud gateway - CircuitBreaker GatewayFilte

前面学习Spring cloud gateway的时候&#xff0c;做测试的过程中我们发现&#xff0c;Spring Cloud Gateway不需要做多少配置就可以使用Spring Cloud LoadBalance的功能&#xff0c;比如&#xff1a; spring:application:name: spring-gatewaycloud:gateway:routes:- id: path…

python通过selenium获取输入框的文本值爬取编辑框内容

以百度首页的输入框为例,当输入‘你好‘后&#xff0c;html中的value的值会变成‘你好’ from selenium import webdriver web webdriver.Chrome() web.get(http://www.baidu.com) # 初始页面 cc web.find_element_by_xpath(//*[id"kw"]) #定位输入通过复制xpat…

提高问卷填写率的策略与方法

在现代社会的研究中&#xff0c;问卷调研是一种常见的数据收集方式。但是&#xff0c;随着数据的快速传播和竞争激烈的市场环境&#xff0c;怎样吸引大量的人填好问卷成为了科研人员关心的问题。本文将介绍一些方式和策略&#xff0c;以帮助你吸引大量的人填好问卷&#xff0c;…

【C语言】位运算实现二进制数据处理及BCD码转换

文章目录 1&#xff0e;编程实验&#xff1a;按short和unsigned short类型分别对-12345进行左移2位和右移2位操作&#xff0c;并输出结果。2&#xff0e;编程实验&#xff1a;利用位运算实现BCD码与十进制数之间的转换&#xff0c;假设数据类型为unsigned char。3&#xff0e;编…

Cisco Packet Tracer配置命令——交换机篇

交换机VLAN配置 在简单的网络环境中&#xff0c;当交换机配置完端口后&#xff0c;即可直接应用&#xff0c;但若在复杂或规模较大的网络环境中&#xff0c;一般还要进行VLAN的规划&#xff0c;因此在交换机上还需进行 VLAN 的配置。交换机的VLAN配置工作主要有VLAN的建立与删…

JS 云服务 Deno Depoly 宣布,推出定时运行功能 Deno Cron

如果需要定时执行 JS 脚本&#xff0c;以后多一个选项。 Web 构建日益复杂。编写现代软件包括利用云基础设施、剖析模板代码和管理复杂的配置&#xff0c;而开发人员只想专注于编写业务逻辑。 Deno 旨在通过删除配置和不必要的模板&#xff0c;从根本上简化 Web 开发。我们将无…

常见的Linux系统版本

在介绍常见的Linux系统版本之前&#xff0c;首先需要区分Linux系统内核与Linux发行套件系统的不同。Linux系统内核指的是一个由Linus Torvalds负责维护&#xff0c;提供硬件抽象层、硬盘及文件系统控制及多任务功能的系统核心程序。而Linux发行套件系统是我们常说的Linux操作系…

openGauss学习笔记-150 openGauss 数据库运维-备份与恢复-物理备份与恢复之gs_backup

文章目录 openGauss学习笔记-150 openGauss 数据库运维-备份与恢复-物理备份与恢复之gs_backup150.1 背景信息150.2 前提条件150.3 语法150.4 参数说明150.5 示例 openGauss学习笔记-150 openGauss 数据库运维-备份与恢复-物理备份与恢复之gs_backup 150.1 背景信息 openGaus…

基于SSM的医院交互系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

二分查找|滑动窗口|前缀和|LeetCode209: 长度最小的子数组

长度最短的子数组 作者推荐 【动态规划】【广度优先】LeetCode2258:逃离火灾 本文涉及的基础知识点 二分查找算法合集 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 滑动窗口 题目 给定一个含有 n 个正整数的数组和一个正整数 target…

ipa文件怎么去除包体内的插件在线签名工具步骤

当开发者完成iOS应用的开发并构建完成后&#xff0c;应用程序会被打包为一个.ipa文件&#xff0c;这是一个iOS App Store的安装包格式。在某些情况下&#xff0c;开发者可能需要去除.ipa文件中包含的插件&#xff08;通常指的是app extension、frameworks或watch apps等&#x…

docker的资源限制及容器应用

一、docker资源限制 在使用 docker 运行容器时&#xff0c;一台主机上可能会运行几百个容器&#xff0c;这些容器虽然互相隔离&#xff0c;但是底层却使用着相同的 CPU、内存和磁盘资源。如果不对容器使用的资源进行限制&#xff0c;那么容器之间会互相影响&#xff0c;小的来说…