Springmvc的全部知识详解(前后台传值,文件上传和下载,拦截器)

SpringMVC-文件上传 拦截器 springmvc文件上传及拦截器 阅读详情

一、什么是SpringMVC

SpringMVC就是一个Spring内置的MVC框架。

MVC框架,它解决WEB开发中常见的问题(参数接收、文件上传、表单验证、国际化等等),而且使用简单,与Spring无缝集成。支持 RESTful风格的URL请求。

采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。

SpringMVC的作用

MVC模式(Model-View-Controller):解决页面代码和后台代码的分离。

SpringMVC原理

在没有使用SpringMVC之前我们都是使用Servlet在做Web开发。但是使用Servlet开发在接收请求参数,数据共享,页面跳转等操作相对比较复杂。servlet是java进行web开发的标准,既然springMVC是对servlet的封装,那么很显然SpringMVC底层就是Servlet,SpringMVC就是对Servlet进行深层次的封装。

回顾MVC模式

MVC分别是:模型model(javabean)、视图view(jsp/img)、控制器Controller(Action/servlet)。

C存在的目的就是为了保证M和V的一致性,当M发生改变时,C可以把M中的新内容更新到V中。

SpringMVC执行流程和原理

img

SpringMVC执行流程:

01、用户发送出请求被前端控制器DispatcherServlet拦截进行处理。 
02、DispatcherServlet收到请求调用HandlerMapping(处理器映射器)。 
03、HandlerMapping找到具体的处理器(查找xml配置或注解配置),生成处理器对象及处理器拦截器(如果有),再一起返回给DispatcherServlet。 
04、DispatcherServlet调用HandlerAdapter(处理器适配器)。 
05、HandlerAdapter经过适配调用具体的处理器(Handler/Controller)。 
06、Controller执行完成返回ModelAndView对象。 
07、HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet。 
08、DispatcherServlet将ModelAndView传给ViewReslover(视图解析器)。 
09、ViewReslover解析ModelAndView后返回具体View(视图)给DispatcherServlet。 
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。 
11、DispatcherServlet响应View给用户。

二、SpringMVC配置文件信息

1.配置pom.xml引入需要的jar

<?xml version="1.0" encoding="UTF-8"?>
​
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
​
  <groupId>org.example</groupId>
  <artifactId>SpringMvc</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>
​
  <name>SpringMvc Maven Webapp</name>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
​
​
    <spring.version>5.2.5.RELEASE</spring.version>
    <aopalliance.version>1.0</aopalliance.version>
    <aspectj.weaver>1.9.2</aspectj.weaver>
    <!-- junit版本号 -->
    <junit.version>4.5</junit.version>
  </properties>
  <dependencies>
    <!-- spring -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-core</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>
​
    <!--切入点表达式的支持-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.6.11</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>compile</scope>
    </dependency>
​
    <!-- Spring-jdbc 用于配置JdbcTemplate -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <!--c3p0-->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
    </dependency>
​
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.17</version>
    </dependency>
​
​
    <!--springmvc-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
​
    <!--文件上传-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.5</version>
    </dependency>
​
    <!--servlet-->
    <!--引入Servlet开始-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    <!--引入Servlet结束-->
    <!--引入jsp相关开始-->
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2</version>
      <scope>provided</scope>
    </dependency>
    <!--引入jsp相关结束-->
    <dependency>
      <groupId>cn.hutool</groupId>
      <artifactId>hutool-all</artifactId>
      <version>5.3.10</version>
    </dependency>
​
    <!--jackson ( 如果spring版本 高于5.0 ,那么Jackson版本 要从2.9开始)-->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-core</artifactId>
      <version>2.9.7</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-annotations</artifactId>
      <version>2.9.7</version>
    </dependency>
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.7</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>RELEASE</version>
      <scope>compile</scope>
    </dependency>
​
​
  </dependencies>
​
​
  <build>
    <!--配置内部tomcat插件-->
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <path>/</path>
          <port>9999</port>
          <uriEncoding>UTF-8</uriEncoding>
        </configuration>
      </plugin>
​
      <!--配置代码生成器插件-->
      <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.2</version>
        <dependencies>
          <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!--此处驱动版本和上面同步-->
            <version>5.1.3</version>
          </dependency>
        </dependencies>
        <configuration>
          <!--配置文件的路径-->
          <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
          <overwrite>true</overwrite>
        </configuration>
      </plugin>
    </plugins>
​
    <!--配置资源打包方式
    解决maven 找不到mapper映射文件:放在resources里面不用配置-->
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
  </build>
</project>
​
2.配置springmvc.xml配置文件,开启注解扫描和视图解析器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
​
    <!--注解扫描-->
    <context:component-scan base-package="com.yzx.controller"/>
​
​
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix"  value="/"/>
        <property name="suffix"  value=".html"/>
    </bean>
    <!--配置全局时间转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.yzx.util.TimeUtil"/>
            </set>
        </property>
    </bean>
    <!--mvc注解驱动,支持mvc的注解 (当前注解驱动,可以解决大多数问题,但是类型转换还需手动引入)-->
    <!--<mvc:annotation-driven/>-->
​
​
    <!--使用全家转换器的话,mvc注解写法-->
    <mvc:annotation-driven conversion-service="conversionService"/>
​
    <!--配置支持静态页面访问 (针对 web.xml中 拦截所有路径的配置)-->
    <mvc:default-servlet-handler/>
​
​
    <!--配置文件上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--请求编码格式-->
        <property name="defaultEncoding" value="utf-8"/>
​
        <!--上传文件大小上限-->
        <property name="maxUploadSize" value="1048576000"/>
​
        <!--上传文件单个大小上限-->
        <property name="maxUploadSizePerFile"  value="10485760"/>
    </bean>
​
    <!--拦截器配置-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--拦截的路径 path语法:/**/*-->
            <mvc:mapping path="/**/*"/>
            <!--放行的路径 -->
            <mvc:exclude-mapping path="/login"/>
            <mvc:exclude-mapping path="/model/**"/>
            <bean class="com.yzx.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>
3.配置web.xml配置中文编码过滤器,解决post乱码问题

<?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">
​
  <!--配置中文编码过滤器,放到springmvc前端控制器上面-->
  <filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <!--配置当前编码过滤器的 规则,指定编码为UTF-8-->
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <!--强制将当前工程的请求和响应编码设置为utf-8-->
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
​
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <!--配置前端控制器-->
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:SpringMvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
​
  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
​
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>login.html</welcome-file>
  </welcome-file-list>
</web-app>

三.获取前台页面参数

1、通过原生HttpServletRequest获取前端参数

前台 jsp:

<fieldset>
  <legend>参数传递方式1--使用HTTPServletRequest</legend>
  <form action="param/param1" method="get">
    账号:<input type="text" name="username"><br>
    密码:<input type="text" name="password"><br>
    <input type="submit" value="提交"><br>
  </form>
</fieldset>

后台 controller:

@Controller
@RequestMapping("/param")
​
//1、通过原生HttpServletRequest获取前端参数
public class ParamController {
    @RequestMapping("/param1")
    public String  param1(HttpServletRequest  request){
        String  username=request.getParameter("username");
        String  password=request.getParameter("password");
        System.out.println(username+"     "+password);
        return "login";
    }

2、前端页面参数和Controller方法参数名一致的获取方式

前台 jsp:

<fieldset>
  <legend>参数传递方式2--方法的参数名和页面参数一致</legend>
  <form action="param/param2" method="post">
    账号:<input type="text" name="username"><br>
    密码:<input type="text" name="password"><br>
    <input type="submit" value="提交"><br>
  </form>
</fieldset>

后台 controller:

//2、前端页面参数和Controller方法参数名一致
    @RequestMapping("/param2")
    public String  param2(String  username,String  password){
        System.out.println(username+"     "+password);
        return "login";
}

前端页面参数和Controller方法参数名不一致的获取方式

前台 jsp:

<fieldset>
  <legend>参数传递方式3--方法参数名和页面参数名称不一致</legend>
  <form action="param/param3" method="post">
    账号:<input type="text" name="username1"><br>
    密码:<input type="text" name="password1"><br>
    <input type="submit" value="提交"><br>
  </form>
</fieldset>

后台 controller:

//2、前端页面参数和Controller方法参数名一致/不一致的获取方式
    @RequestMapping("/param3")
       public String  param3(@RequestParam("username1")String  username, @RequestParam("password1")String  password){
         System.out.println(username+"    param3    "+password);
         return "login";
}

3、通过对象接收前端参数(包含对象类型参数和集合类型参数)中文乱码的配置

前台 jsp:

<fieldset>
  <legend>参数传递方式3--参数过多使用对象作为参数</legend>
  <form action="param/param4" method="post">
    账号:<input type="text" name="username"><br>
    密码:<input type="text" name="password"><br>
    <input type="submit" value="提交"><br>
  </form>
</fieldset>

后台 controller:

//3、通过对象接收前端参数(包含对象类型参数和集合类型参数)中文乱码的配置

ava@RequestMapping("/param4")
public String  param4(User user){
    System.out.println(user);
    return "login";
}

4、时间类型参数的转换问题 ConversionServiceFactoryBean的配置

(1) springmvc资源文件配置mvc注解驱动和配置支持静态页面访问

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       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
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
​
    <!--注解扫描-->
    <context:component-scan base-package="com.yzx.controller"/>
​
​
        
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix"  value="/"/>
        <property name="suffix"  value=".jsp"/>
    </bean>
    <!--配置全局时间转换器-->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.yzx.util.TimeUtil"/>
            </set>
        </property>
    </bean>
    <!--mvc注解驱动,支持mvc的注解 (当前注解驱动,可以解决大多数问题,但是类型转换还需手动引入)-->
    <!--<mvc:annotation-driven/>-->
​
​
    <!--使用全家转换器的话,mvc注解写法-->
    <mvc:annotation-driven conversion-service="conversionService"/>
​
    <!--配置支持静态页面访问 (针对 web.xml中 拦截所有路径的配置)-->
    <mvc:default-servlet-handler/>
</beans>

(2) 具体实现:

① 第一种实现(实体类注解实现)

//时间类型
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private   Date    time;

② 第二种实现(数据库和实体类通过string类型记录时间)

③ 第三种实现(通过创建时间类型转换的类,然后在springmvc中配置全局日期时间转换器)

package com.yzx.util;
​
import cn.hutool.core.util.StrUtil;
import org.springframework.core.convert.converter.Converter;
​
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
​
public class TimeUtil implements Converter <String,Date>{
​
​
    @Override
    public Date convert(String s) {
        if(StrUtil.isEmpty(s)){
            throw   new RuntimeException("时间类型不允许为空");
        }
//        else  if(s.length()!=10){
//            throw new RuntimeException("时间格式错误,应该是年月日的格式!");
//        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date parse = null;
        try {
            parse=sdf.parse(s);
            return parse;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

​

前台jsp:

<fieldset>
  <legend>参数传递方式5--包含时间类型,需要类型转换</legend>
  <form action="param/param5" method="post">
    账号:<input type="text" name="username"><br>
    密码:<input type="text" name="password"><br>
    日期:<input type="datetime-local" name="time"><br>
    <input type="submit" value="提交"><br>
  </form>
</fieldset>

后台 controller:

//4、时间类型参数的转换问题 ConversionServiceFactoryBean的配置
    @RequestMapping("/param5")
     public String  param5(User user){
       System.out.println(user);
       return "login";
}

四、后台传值到前台

1、使用ModelAndView传值(普通值和map集合)

前台jsp:

${str}<br>
${name}<br>
${age}

后台controller:

@Controller
@RequestMapping("/model")
public class ModelController {
    //1、使用ModelAndView传值(普通值和map集合)
    @RequestMapping("/test1")
    public ModelAndView  test1(ModelAndView  mv){
        mv.addObject("str","你好");
        Map map=new HashMap();
        map.put("name","小杨");
        map.put("age","20");
        mv.addAllObjects(map);
        mv.setViewName("test");
        return mv;
    }

2、使用Model传值

前台jsp:

${str}<br>
${name}<br>
${age}

后台controller:

  //2、使用Model传值
    @RequestMapping("/test2")
    public  String  test2(Model m){
        m.addAttribute("str","你好");
        Map map=new HashMap();
        map.put("name","老范");
        map.put("age","19");
        m.addAllAttributes(map);
        return  "test";
    }

3、使用普通对象(javabean对象传值)默认提示根据配置返回的jsp页面

前台jsp:

首先在webapp下面建一个model包 在model下面建一个test3.jsp测试

${user}

后台controller: user是封装的实体对象

    
//3、使用普通对象(javabean对象传值)默认提示根据配置返回的jsp页面
    @RequestMapping("/test3")
    public  User  test3(){
        User  user=new  User("123","456");
        return  user;
    }

4、使用redirect跳过视图解析器 如redirect:/login.html

后台controller:

//4、使用redirect和forward的使用  ,跳过视图解析器
    @RequestMapping("/test5")
    public String test5() {
        return "redirect:/login.html";
    }

使用forward跳过视图解析器 如forward:/login.html

后台controller:

//4使用forward跳过视图解析器
    @RequestMapping("/test6")
    public String test6() {
        return "forward:/login.html";
    }

五、文件上传和文件下载

文件上传

创建一个upload.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    注意name "uploadFile" 一定要和后台一样
<form action="/upload/upload" method="post" enctype="multipart/form-data">
    头像:<input type="file" name="uploadFile"><br/>
    <input type="submit" value="提交">

</form>
</body>
</html>

配置文件上传解析器 :

 <!--配置文件上传解析器-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--请求编码格式-->
        <property name="defaultEncoding" value="utf-8"/>

        <!--上传文件大小上限-->
        <property name="maxUploadSize" value="1048576000"/>

        <!--上传文件单个大小上限-->
        <property name="maxUploadSizePerFile"  value="10485760"/>
    </bean>

控制层 controller

@Controller
@RequestMapping("/upload")
public class UploadController {
    @RequestMapping("/upload")
    @ResponseBody
    public String  upload(MultipartFile  uploadFile, HttpServletRequest  request){
        String  originalFilename=uploadFile.getOriginalFilename();//获取原始文件名称
        System.out.println(originalFilename);

        //目的仓库地址在项目内部
        //String  upload=request.getServletContext().getRealPath("upload");//存储文件的文件夹路径

        //目的仓库地址在项目内部
        String  upload="D:\\upload";
        System.out.println(upload);
        //与目的地建立连接
        File file=new File(upload);
        if(!file.exists()){//判断是否存在,不存在创建
            file.mkdirs();
        }
        //获取文件后缀名
        String  suffix=originalFilename.substring(originalFilename.lastIndexOf("."),originalFilename.length());
        //构建文件上传具体路径
        String  filename=upload.concat(File.separator).concat(UUID.randomUUID().toString()).concat(suffix);
        System.out.println(filename);
        try {
            //上传
            uploadFile.transferTo(new File(filename));
            return filename;
        } catch (IOException e) {
            e.printStackTrace();
        }
     return null;
    }

文件下载

文件上传和文件下载的区别是控制层的不同 控制层 controller

/** * 文件下载 * ResponseEntity进行返回的 */ @RequestMapping("/download") public ResponseEntity<byte[]> download(HttpServletRequest request,String filename){ //文件地址在项目内部的(目的地址信息) //String upload=request.getServletContext().getRealPath("upload");

 //目的仓库在项目之外
    String  upload="D:\\upload";
    //先拼接具体的位置路径,然后通过file进行建立连接
    File file=new File(upload+File.separator+filename);
    if(!file.exists()){//如果不存在文件,直接返回null
        return null;
    }

    try {
        //创建标头文件对象
        HttpHeaders  headers=new HttpHeaders();
        //解决乱码问题
        String  downloadfile=new String(filename.getBytes(StandardCharsets.UTF_8),"iso-8859-1");
        //以下载的方式打开文件
        headers.setContentDispositionFormData("attachment",downloadfile);
        //二进制流
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers, HttpStatus.CREATED);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();

    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;

}

六、拦截器

Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。

用户可以自己定义一些拦截器来实现特定的功能。它也是 AOP 思想的具体应用。自定义拦截器, 要求必须实现:HandlerInterceptor 接口

过滤器和拦截器区别:

过滤器是 servlet 规范中的一部分,任何 java web 工程都可以使用。

拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。

过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。

拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp,html,css,image 或者 js 是不会进行拦截的。

配置拦截器

springmvc.xml

<!--拦截器配置-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--拦截的路径 path语法:/**/*-->
            <mvc:mapping path="/**/*"/>
            <!--放行的路径 -->
            <mvc:exclude-mapping path="/login"/>
            <mvc:exclude-mapping path="/model/**"/>
            <bean class="com.yzx.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>
控制层用seeion传user到LoginInterceptor

@Controller
@RequestMapping
public class LoginController {

    @RequestMapping("/login")
    @ResponseBody
    public  Object  login(String username, String  password, HttpSession  session){
        if(StrUtil.isNotEmpty(username)&&StrUtil.isNotEmpty(password)){
            System.out.println("登录");
            session.setAttribute("user","user");
        }else{
            System.out.println("退出");
            session.removeAttribute("user");
        }

        return null;
    }
}

创建com.yzx.interceptor.LoginInterceptor

package com.yzx.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 拦截器
 */
public class LoginInterceptor implements HandlerInterceptor {
    /**
     * 预处理种,返回true是放行,  返回false是拦截
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object  user=request.getSession().getAttribute("user");
        if(user!=null){
            System.out.println(true);
            return true;
        }else{
            System.out.println(false);
            response.sendRedirect("/login.html");
            return  false;
        }
    }
}

【SpringMVC 】什么是SpringMVC(三)?基于springmvc的文件上传、基于springmvc的拦截器、基于springmvc的邮件发送 @@@@@@@@@@@邮件发送 通过java进行邮件发送,会涉及到两种协议: 1、smtp 简单邮件传输协议 作用:用于指定如何发送邮件 2、pop3 邮局协议版本3 作用:用于指定如何接收邮件 @@@@@@@@我们在进行邮件发送时,首先需要开通邮箱的这两个协议 @@@@@@@@邮件发送的过程 此处,我们以QQ邮箱为例,进行配置,准备工作 登录QQ邮箱,开通smtp,pop3协议 阅读详情

相关推荐

【Agora 本地录制最全总结- 基于Java SDK】

Agora 本地服务端录制

lizhengze1117的博客 1790

springMVC实现文件下载

springMVC实现文件下载 一、文件下载原理 1、设置 response 响应头 2、读取文件 -- InputStream 3、写出文件 -- OutputStream 4、执行操作 5、关闭流 (先开后关) 二、实现代码 @RequestMapping(value="/downloadFile") public St

HaHa_Sir的博客 1万+

ZEMAX学习第7天-手机镜头光学系统设计全过程案例

接下来对系统微调,依次缩小CRA和畸变,首先对CRA进行依次递减(39°、38°、37°、36°、35°),目前CRA角度40度,每次下降一度进行优化,利用MAXX加OPLT一起控制,控制小于35°。可以看出在标注的三个地方镜头曲率变化,导致PY=1的光线走向奇特,因此需要对矢高进行调整,按照标注的地方依次调整(从右到左)至传函变好,越靠近右边对其余视场影响越小。3.圆锥系数值较大,透镜形状怪异;一、第1,3镜子偏厚,第4镜子偏薄,45镜子间隔边缘偏小,第5片镜子中心厚度与边缘厚度相差较大,需要控制;

liningliwei的博客 1067

【SpringMVC学习06】SpringMVC文件上传与下载

  文件的上传和下载是项目开发中最常用的功能,例如图片的上传与下载、 邮件附件的上传与下载等。 接下来,将对 Spring MVC 环境中文件的上传和下载进行讲解。 一、文件上传概述   多数文件上传都是通过表单形式提交给后台服务器的,因此,要实现文件上传功能,就需要 提供一个文件上传的表单,而该表单必须满足以下 3 个条件。 form 表单的 method 属性设置为 post。 form 表...

weixin_43800761的博客 425

国产Flash替代方案:手把手教你用XSCT烧写ZYNQ7045的BOOT.BIN(附完整命令解析)

本文详细介绍了国产Flash替代方案在ZYNQ7045上的应用,通过XSCT工具链实现BOOT.BIN的精准烧写。内容涵盖国产Flash兼容性检查、PetaLinux环境搭建、XSCT烧写全流程及故障排查,帮助开发者高效完成国产化替代,提升硬件开发效率。

weixin_33670786的博客 426

【Python爬虫】爬取企业专利信息

本来是个美好的周末的,但是周五晚上领导给了一个公司名称的Excel,让把这些公司的专利信息爬取下来。本文记录了爬取企业专利信息的心酸过程。码字不易,喜欢请点赞!!! 一、找寻目标网页 在接到这个任务之后,我的内心是拒绝的。但是又不能不干。因此首先我需要先找到有公司专利信息的地方。在一番查找和问了问朋友之后,我知道中国专利网、国家知识产权网、Incopat、天眼查、企查查这些网站上面都有企业的专利...

Asher117的博客 2万+

解决Postman发送请求报错org.springframework.web.bind.MissingServletRequestParameterException

异常现象 最近使用Postman调试接口时出现报错如下: org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'userId' is not present 问题原因 首先从报错的字面信息来理解,是说有一个必填参数没有传值; 如果这个参数是非必填参数的话,我们应该设置该参数的required属性为false: @RequestParam(required = fals

u800820的专栏 2万+

MicroCap声学仿真介绍(二)-创建声学仿真元件

声学库里包含孔、管、障板辐射器等器件,我们只需要按照仿真的需求,将声学库里的器件排列好,输入参数,用线连接起来即可。这里我们用D指代孔的直径,L指代孔的长度,N代表孔的数量。26.在弹出的界面中做如下设置:需要先在右面的选框里找到对应的项,然后右键Add Part,再之后就如下设置。3.在弹出的界面中,选择“Macro file(.mac)”,并点击右上角的“OK”下面就以声学仿真中常见的“孔”来做示例,跟大家一块演示一下宏程序的新建。10.在上图中“Value”中填入“R”,然后点击左边的“OK”按钮;

山无忧的博客 2199

SpringMVC | SpringMVC中的 “文件上传和下载”

目录: 一、文件上传 1.1 文件上传“概述” 1.2 文件上传“具体配置” : “前端”中配置“文件上传” ( type=“file” + 满足3个条件 ) “后端”中配置“文件上传” ( 配置id为“CommonsMultipartResolver”的bean + 配置“文件上传”的“约束条件” + 通过“MultipartFile接口”参数接收“传来的文件”) 1.3 文件上传“应用案例” : 文件上传 (存储在“相对路径”) 文件上传 (存储在“绝对路径”) 二、文件下载 .....

m0_70720417的博客 3270

从养殖场到科技前沿:YOLOv11+OpenCV精准计数鸡蛋与鸡

YOLOv11结合OpenCV技术,精准识别和计数鸡蛋与鸡,广泛应用于养殖场、市场监控和自动化包装。通过深度学习与计算机视觉,提升农业生产效率,让智能化管理更简单高效。

专注于深入研究多种编程语言,以实战为导向,逐步拓展开发技能,提升工程化编码和思维能力,展现无敌技术实力。 1205

世界模型(World Models)进展全景调研(截至 2025-08)

A5) 2019-07(待核验) | C-SWM:Contrastive Structured World Models(Kipf et al.)A6) 2019-07(待核验) | SLAC:Stochastic Latent Actor-Critic(Lee et al.)A3) 2015-12(背景注记,待核验) | Embed to Control(E2C,Watter et al.)Nature 2020)Repro/Code:werner-duvaud/muzero-general(社区)

u013250861的博客 488

SpringMVC系列(四)之SpringMVC实现文件上传和下载

springmvc的文件上传和下载

lijie1025的博客 2180

【系统架构设计师】预测试卷十:综合知识(75道选择题)

本文包含75道选择题,覆盖计算机系统、操作系统、网络、数据库、软件工程等核心知识域,其中系统架构设计与评估占比最高(19题)。题目难度稍高,注重灵活应用,题干全新且不与前8套重复。部分典型题目解析包括:计算机性能比较(CPU时间公式TLB/页表机制)、Cache写策略、流水线分支惩罚、管程条件变量、LRU近似算法、自旋锁适用场景、TCP字节流特性、Anycast应用、MVCC机制、分布式事务选型等。答案详解强调易错点,如性能比较需综合计算、TLB缺失不等于缺页、

数据知道的博客 478

狂神说SpringMVC08:拦截器+文件上传下载

狂神说SpringBoot系列连载课程,通俗易懂,基于SpringBoot2.2.5版本,欢迎各位狂粉转发关注学习。未经作者授权,禁止转载这是SpringMVC视频同步的最后一章:拦截器...

狂神说 9573

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

JSP-SpringMVC(一)传参、传值、拦截器、文件上传

目录 1.传参方式: 2.中文乱码问题: 3.访问路径: 4.定义拦截器 5.传值方式: 6.文件上下传: 7.文件下载 8.将返回的对象解析成JSON字符串 1.传参方式: SpringMVC的传参方式: 四种形式 @Controller public class ParaControlloer { @RequestMapping("/param1") /...

忆_恒心的博客 781

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

SpringMVC【Ajax、拦截器、文件上传和下载】

目录:一、Ajax使用:二、SpringMVC拦截器三、文件上传和下载 一、Ajax使用: 1. index.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>首页</title> <script src="${pageContext.request.contextPath}/static

程序员战胜 1753

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

SpringMVC——拦截器及文件上传和下载

目录 自定义拦截器 拦截器类 在springmvc的配置文件中配置拦截器 文件上传 导入jar包 配置bean:multipartResolver 采用file.Transto 来保存上传的文件 ...

6。 439

SpringMVC(文件上传和下载 ,SpringMVC拦截器,转发和重定向)

1.转发: 方式一:使用传统的方法转发: 方式二:SpringMVC的转发: 关键字:forward 2.重定向: 传统方式: 关键字方式: 小结:1. springMVC遇到关键字redirect 或者 forward时,则默认开启重定向和转发操作, 要求返回值类型是Spring说明: 如果跳转首页 通过IndexController配置 比较繁琐. 所以SpringMVC通过视图控制器 跳转首页.框

2302_77790337的博客 1197

AJAX | 拦截器、文件上传和下载

AJAX | 拦截器、文件上传和下载

wei_shuo的博客 1327

【SpringMVC】SpringMVC拦截器,统一异常处理,文件上传与下载

本文详细介绍了SpringMVC中的拦截器,统一异常处理,以及文件的上传与下载

Answer的博客 833

【SpringMVC笔记】拦截器 + 文件上传下载

拦截器 + 文件上传下载拦截器(interceptor)自定义拦截器验证用户是否登录 (认证用户)没有拦截器配置拦截器文件的上传文件输出流进行文件上传file.Transto 进行文件上传文件的下载 拦截器(interceptor) SpringMVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行 预处理 和 后处理。开发者可以自己定义一些拦截器来实现特定的功能。 过滤器与拦截器的区别:拦截器是 AOP 思想的具体应用。 过滤器(filter): servlet 规

萌宅鹿的技术小屋 1047

文件上传、下载、异常、拦截器

文件上传、下载、异常、拦截器

qq_65186476的博客 1587

SpringMVC-拦截器+文件上传下载

文章目录概述过滤器与拦截器的区别过滤器拦截器自定义拦截器程序结构拦截器定义配置拦截器控制层调用Http接口访问验证用户是否登录 (认证用户)实现思路测试总程序结构控制层【重要】拦截器【重要】首页登录页成功页文件上传下载首页配置控制层upload1upload2download 概述 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。开发者可以自己定义一些拦截器来实现特定的功能。 过滤器与拦截器的区别 拦截器是AOP思想的具体应用。 过滤器 ser

王寒寒的博客 751

SpringMVC——处理json、文件上传和下载、拦截器、国际化

SpringMVC——处理json、文件上传和下载、拦截器、国际化一、springmvc处理json1.1 HttpMessageConverter介绍1.2 SringMVC响应json数据示例1.3 发送json数据给服务器示例1.4 HttpEntity、ResponseEntity 示例二、文件上传和下载三、拦截器3.1 自定义拦截器3.2 拦截器方法执行顺序3.3 拦截器源码分析(待补)四、国际化4.1 国际化简介4.2 步骤4.2 点击链接切换国际化 一、springmvc处理json 1.1

weixin_44630656的博客 853

SpringMVC系列十一: 文件上传与自定义拦截器

SpringMVC系列十一: 文件上传与自定义拦截器

你好, 我在学java的博客 1171

SpringMVC---拦截器、文件上传下载

18 拦截器 18.1 概述 SpringMVC中的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理处理器进行预处理或者是后处理。 过滤器和拦截器的区别:拦截器是AOP思想的具体应用。 过滤器 servlet规范中的一部分,任何JavaWeb工程都可以使用。 在url-pattern中配置了/*之后,可以对所有要访问的资源进行拦截。 拦截器 拦截器是SpringMVC框架自己实现的,只有使用了SpringMVC框架的工程才能使用。 拦截器只会拦截访问的控制器方法(Controll

Srwici的博客 305
上一篇: SpringMVC文件上传和下载
下一篇: Spring 框架事务管理机制,和实现方式
变成秃头怪
博客等级 码龄5年 47粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值