4-SpringMVC

news2024/11/25 20:51:50

文章目录

  • 项目源码地址
  • 回顾-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.coloradmin.cn/o/1301327.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通过生成模拟释放无限数据以实现机器人自动化学习

该工作推出RoboGen&#xff0c;这是一种生成机器人代理&#xff0c;可以通过生成模拟自动大规模学习各种机器人技能。 RoboGen 利用基础模型和生成模型的最新进展。该工作不直接使用或调整这些模型来产生策略或低级动作&#xff0c;而是提倡一种生成方案&#xff0c;该方案使用…

分子生成领域的stable diffusion - GEOLDM

一、关于stable diffusion 很多人都知道stable diffusion&#xff0c;stable diffusion的出现改变了机器生成领域&#xff0c;让AI技术第一次无比的接近正常人。大语言模型&#xff0c;AIGC概念于是兴起。基于stable diffusion 大家开发了lora&#xff0c; hyperwork等微调技术…

React-hooks

1 hooks使命 #逻辑组件复用 逻辑与UI组件分离 React 官方推荐在开发中将逻辑部分与视图部分结耦&#xff0c;便于定位问题和职责清晰 函数组件拥有state 在函数组件中如果要实现类似拥有state的状态&#xff0c;必须要将组件转成class组件 逻辑组件复用 社区一直致力于逻辑…

【数据结构高阶】红黑树

目录 一、红黑树的概念 二、红黑树的性质 2.1 红黑树与AVL树的比较 三、红黑树的实现 3.1 红黑树节点的定义 3.2 数据的插入 3.2.1 红黑树的调整思路 3.2.1.1 cur为红&#xff0c;f为红&#xff0c;g为黑&#xff0c;u存在且为红 3.2.1.2 cur为红&#xff0c;f为红&am…

Seata配置

参考教程 seata 分布式事务的环境搭建与使用 Seata 1.4.0 nacos配置和使用&#xff0c;超详细 Seata 1.4.2 的安装 Nacos的配置和使用 官网下载地址 本文以v1.4.1为例 1.数据库及表的创建 创建seata数据库&#xff0c;创建以下表&#xff08;右键连接-》新建数据库seata-》…

MVC Gantt Wrapper:RadiantQ jQuery

The RadiantQ jQuery Gantt Package includes fully functional native MVC Wrappers that let you declaratively and seamlessly configure the Gantt component within your aspx or cshtm pages just like any other MVC extensions. 如果您还没有准备好转向完全基于客户端…

天池SQL训练营(二)-SQL基础查询与排序

-天池龙珠计划SQL训练营 Task02&#xff1a;SQL基础查询与排序 SQL训练营页面地址&#xff1a;https://tianchi.aliyun.com/specials/promotion/aicampsql 一、SELECT语句基础 1.1 从表中选取数据 SELECT语句 从表中选取数据时需要使用SELECT语句&#xff0c;也就是只从表…

unity 2d 入门 飞翔小鸟 死亡 显示GameOver(十四)

1、添加Img create->ui->img 把图片拖进去 2、和分数一样、调整位置 3、修改角色脚本 using System.Collections; using System.Collections.Generic; using UnityEngine;public class Fly : MonoBehaviour {//获取小鸟&#xff08;刚体&#xff09;private Rigidbod…

题目:肖恩的乘法表(蓝桥OJ 3404)

题目描述&#xff1a; 解题思路&#xff1a; 本题采用二分中的二分答案。且本题check()用不到开数组&#xff0c;所以不需要开数组&#xff0c;脑海中想象一个数组就好了 题解&#xff1a; #include<bits/stdc.h> using namespace std; using ll long long;ll n, m , k…

C# 图解教程 第5版 —— 第17章 转换

文章目录 17.1 什么是转换17.2 隐式转换17.3 显示转换和强制转换17.4 转换的类型17.5 数字的转换17.5.1 隐式数字转换17.5.2 溢出检测上下文17.5.3 显示数字转换 17.6 引用转换17.6.1 隐式引用转换17.6.2 显式引用转换17.6.3 有效显式引用转换 17.7 装箱转换17.7.1 装箱是创建副…

Python 全栈体系【四阶】(三)

第三章 matplotlib 一、基本绘图 1. 绘图核心 API 案例&#xff1a; 绘制简单直线 import numpy as np import matplotlib.pyplot as plt# 绘制简单直线 x np.array([1, 2, 3, 4, 5]) y np.array([3, 6, 9, 12, 15])plt.plot(x, y) plt.show() # 显示图片&#xff0c;阻塞…

《Mamba: Linear-Time Sequence Modeling with Selective State Spaces》阅读笔记

论文标题 《Mamba: Linear-Time Sequence Modeling with Selective State Spaces》 作者 Albert Gu 和 Tri Dao 初读 摘要 Transformer 架构及其核心注意力模块 地位&#xff1a;目前深度学习领域普遍的基础模型。 为了解决 Transformers 在长序列上的计算效率低下的问题…

【视频笔记】古人智慧与修行

古人的智慧 相由心生、老子悟道、佛祖成佛 多一些思考&#xff0c;多一些精神修炼。 除非我们今天能够产生与人类科技发展相并行的精神变革&#xff0c;否则永远可能也无法跳脱出历史的轮回。 视频来源 曾仕强教授周易的智慧 太极两仪四象八卦 一生二&#xff0c;二生三&…

gRPC基本用法:以人脸识别为例,搭建一个简单的gRPC服务

标题 0. gRPC简介 相关网站&#xff1a; 中文文档&#xff1a;gRPC 官方文档中文版_V1.0 官网&#xff1a;gRPC 介绍&#xff08;以下引自官方文档中文版中的介绍&#xff09;&#xff1a; gRPC是一个高性能、开源和通用的 RPC 框架&#xff0c;面向移动和 HTTP/2 设计。目前提…

LANDSAT_7/02/T1/RAW的Landsat7_C2_RAW类数据集

Landsat7_C2_RAW是指Landsat 7卫星的数据集&#xff0c;采用的是Collection 2级别的数据处理方法&#xff0c;对应的是Tier 1级别的原始数据&#xff08;RAW&#xff09;。该数据集包括了Landsat 7卫星从1999年4月15日开始的所有数据&#xff0c;共涵盖了全球范围内的陆地和海洋…

性格内向怎么办?如何改变性格内向?

性格内向和外向并没有优劣之分&#xff0c;性格内向也不是坏事&#xff0c;但从人际交往和事务处理的角度来看&#xff0c;内向性格确实不如外向的有优势&#xff0c;所以这也是很多人希望改变自己内向性格的原因。 此外性格内向也容易称为心理问题的替代词&#xff0c;比如&a…

Data Mining数据挖掘—2. Classification分类

3. Classification Given a collection of records (training set) – each record contains a set of attributes – one of the attributes is the class (label) that should be predicted Find a model for class attribute as a function of the values of other attribu…

【Linux】进程间通信之共享内存/消息队列/信号量

文章目录 一、共享内存的概念及原理二、共享内存相关接口说明1.shmget函数2.ftok函数3.shmat函数4.shmdt函数5.shmctl函数 三、用共享内存实现server&client通信1.shm_server.cc2.shm_client.cc3.comm.hpp4.查看ipc资源及其特征5.共享内存的优缺点6.共享内存的数据结构 四、…

ADAudit Plus:强大的网络安全卫士

随着数字化时代的不断发展&#xff0c;企业面临着越来越复杂和多样化的网络安全威胁。在这个信息爆炸的时代&#xff0c;保护组织的敏感信息和确保网络安全已经成为企业发展不可或缺的一环。为了更好地管理和监控网络安全&#xff0c;ADAudit Plus应运而生&#xff0c;成为网络…

【队列】数据也得排队

目录 引言 队列的概念 队列的实现 单向链表队列 结构 初始化 入队 出队 取队头 取队尾 求个数 判空 内存释放 总结 引言 队列&#xff0c;这个看似普通的数据结构&#xff0c;其实隐藏着无尽的趣味和巧思。就像单向链表这把神奇的魔法钥匙&#xff0c;它能打开队…