SpringMVC
SpringMVC
SSM:Mybatis + Spring + SpringMVC
依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<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>
- 新版的Spring框架需要用到Tomcat 10和jakarta.servlet才能跑
回顾
Model 1
JSP同样也做Servlet的事
MVC三层架构
- Model:Dao、Service
- 提供要展示的数据
- View:JSP
- 负责Model的展示
- Controller:Servlet
- 接收用户请求并交给Model处理

Servlet
依赖:
JDK 8 + Tomcat 9
<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>
HelloServlet.java
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//取得参数
String method = req.getParameter("method");
if (method.equals("add")){
req.getSession().setAttribute("msg","执行了add方法");
}
if (method.equals("delete")){
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);
}
}
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>hello</servlet-name>
<servlet-class>com.lu.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
测试:
- 访问http://localhost:8080/hello?method=add
- 访问http://localhost:8080/hello?method=delete
疑问
- 碰到一个问题,如果创建普通Maven项目然后添加框架支持的话,webapp下的JSP直接不会去编译,不是出错,而是直接不编译,找了好久没找到问题
HelloSpringMVC
通过配置文件实现
环境:JDK 8 + Tomcat 9
- 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">
<!--配置DispatchServlet:这个是SpringMVC的核心:请求分发器,前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatchServlet要绑定Spring的配置文件-->
<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中, / /*
/:只匹配所有的请求,不会去匹配jsp
/*:匹配所有请求,包括jsp页面
-->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 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"/>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
<!--BeanNameUrlHandlerMapping:匹配的id(Handler)-->
<!--Handler-->
<bean id="/hello" class="com.lu.controller.HelloController"/>
</beans>
- HelloController.java
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView mv = new ModelAndView();
//业务代码
String msg = "helloWorld";
mv.addObject("msg",msg);
//视图跳转
mv.setViewName("text");//需要拼接的视图名称,参考视图解析器的代码实际地址就是(/WEB-INF/jsp/text.jsp)
return mv;
}
}
SpringMVC流程

通过注解实现
处理JDK版本问题
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
处理Maven中资源过滤问题
<build>
<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>
- 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>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<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>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 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="com.lu.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>
- HelloController.java
@Controller
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/h1")
public String hello(Model model) {
model.addAttribute("msg", "helloWorld, Annotation");
return "hello";
}
}
- 访问http://localhost:8080/hello/h1测试
Controller
实现方式
接口
- 样例
- 方法较老,且一个Controller类只能实现一个方法
注解
- 样例
- 方便且好用
RequestMapping
配置访问的URL
@Controller
@RequestMapping("/test")
public class RequestMappingController {
@RequestMapping("/t1")
public String test(Model model) {
String msg = "helloController";
model.addAttribute("msg", msg);
return "test";
}
}
- 访问https://localhost:808/test/t1测试
RestFul
用URL路径传变量
@Controller
public class RestFulController {
// 原来: http://localhost:8080/add?a=1&b=1
// RestFul: http://localhost:8080/add/1/2
@RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.GET)
public String test(@PathVariable int a, @PathVariable int b, Model model) {
int res = a + b;
model.addAttribute("msg", "结果为: " + res);
return "test";
}
}
- 可以显式定义提交方式
method = RequestMethod.GET
,也可直接使用GetMapping或PostMapping
等 - 因此可以通过同个路径,根据不同的
method
,调用不同的方法
@RequestMapping(value = "/add/{a}/{b}", method = RequestMethod.GET)
@GetMapping("/add/{a}/{b}")
@PostMapping("/add/{a}/{b}")
好处:
- 路径更简洁、安全
- 获得参数更方便,框架会自动进行类型转换
- 通过路径可以约束访问参数
- 假设正确访问形式为test/a/1,如果路径变为test/1/a则找不到对应方法
结果跳转方式
- Web资源的路径是以webapp或web文件夹为开始
测试过程中,将视图解析器注释掉
@Controller
public class ResultController {
@RequestMapping("/m/t1")
public String test01(HttpServletRequest request, HttpServletResponse response, Model model) {
HttpSession session = request.getSession();
String msg = session.getId();
model.addAttribute("msg", msg);
// return "forward:/WEB-INF/jsp/test.jsp";
return "/WEB-INF/jsp/test.jsp"; // 转发, 路径不会改变
}
@RequestMapping("/m/t2")
public String test02(HttpServletRequest request, HttpServletResponse response, Model model) {
HttpSession session = request.getSession();
String msg = session.getId();
model.addAttribute("msg", msg);
return "redirect:/index.jsp"; // 重定向, 路径会改变
// 配置了视图解析器, 重定向也要写全路径
}
}
前端数据处理
偷懒
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private int age;
}
取前端数据
UserController.java
@Controller
public class UserController {
// http://localhost:8080/u1?name=lct
@RequestMapping("/u1")
public String test01(String name) {
System.out.println(name);
return "test";
}
// http://localhost:8080/u2?username=lct
@RequestMapping("/u2")
public String test02(@RequestParam("username") String name) {
System.out.println(name);
return "test";
}
// http://localhost:8080/u3?name=lct&age=10&id=2
// 对象属性名要相同, 但顺序可以不相同
@RequestMapping("/u3")
public String test02(User user) {
System.out.println(user);
return "test";
}
}
乱码问题
- 设计一个表单
<html>
<body>
<form action="/mess" method="post">
<label>
<input type="text" name="name">
</label>
<input type="submit">
</form>
</body>
</html>
- 编写Controller
@Controller
public class MessController {
@RequestMapping("/mess")
public String test(Model model, String name) {
model.addAttribute("msg", name);
return "test";
}
}
- 在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>
如果这样乱码还未解决
方式一:查看并修改Tomcat下的config目录中的server.xml
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
方式二:终极乱码过滤器
/**
* 解决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;
}
}
拦截器
过滤器与拦截器的区别:拦截器是AOP思想的具体应用,是横切进项目的
过滤器
- servlet规范中的一部分,任何JavaWeb工程都可以使用
- 在url-pattern中配置了/*之后,可以对所有要访问的资源进行过滤拦截
拦截器
- 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
- 拦截器只会拦截访问的控制器方法,即controller中的请求
- 如果访问的是静态资源,如jsp,html,css,image,js是不会进行拦截的
配置
<!-- 拦截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<!--/** 包括路径及其子路径-->
<!--/admin/* 拦截的是/admin/add等等这种 , /admin/add/user不会被拦截-->
<!--/admin/** 拦截的是/admin/下的所有-->
<mvc:mapping path="/**"/>
<bean class="com.lu.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
样例
TestController.java
@RestController
public class TestController {
@RequestMapping("/t1")
public String test() {
System.out.println("TestController => test()执行");
return "OK";
}
}
MyInterceptor.java
public class MyInterceptor implements HandlerInterceptor {
/*
在请求处理的方法之前执行
return true执行下一个拦截器
return false就不执行下一个拦截器
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("------------处理前------------");
return true;
}
}
登录判断验证
index
页面上有两个a
标签- 分别对应登录和首页
- 如果未登录,点击首页会被拦截器转到登录页面
- 拦截器放行条件
- 请求路径包含
login
session
中的userInfo
不为空
- 请求路径包含
- 满足任意一条放行条件则正常请求,否则转发到登录页面
LoginController.java
@Controller
@RequestMapping("/user")
public class LoginController {
@RequestMapping("/main")
public String toMainPage() {
return "main";
}
@RequestMapping("/gologin")
public String toLoginPage() {
return "login";
}
@RequestMapping("/login")
public String login(HttpSession session, String username, String password) {
session.setAttribute("userInfo", username);
return "main";
}
@RequestMapping("/logout")
public String logout(HttpSession session) {
session.removeAttribute("userInfo");
return "login";
}
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<body>
<a href="${pageContext.request.contextPath}/user/go">登录</a>
<a href="${pageContext.request.contextPath}/user/main">首页</a>
</body>
</html>
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>登录页面</h1>
<form action="${pageContext.request.contextPath}/user/login" method="post">
用户名:<input type="text" name="username">
密码:<input type="text" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>首页</h1>
${userInfo}
<a href="${pageContext.request.contextPath}/user/logout">注销</a>
</body>
</html>
LoginInterceptor.java
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (request.getRequestURI().contains("login")) {
return true;
}
HttpSession session = request.getSession();
if (session.getAttribute("userInfo") != null) {
return true;
}
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
return false;
}
}
拦截器配置
<!-- 拦截器配置 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/>
<bean class="com.lu.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
文件上传下载
依赖
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!--servlet-api导入高版本的-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
前端测试页面
- 前端表单要求
- 为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data
- 只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/upload" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
</form>
<a href="${pageContext.request.contextPath}/download">点击下载</a>
</body>
</html>
MVC配置
- Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的
- 这个bena的id必须为:multipartResolver ,否则上传文件会报400的错误!
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容,默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/>
<!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
上传
FileController.java
@Controller
public class FileController {
//@RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile 对象
//批量上传CommonsMultipartFile则为数组即可
@RequestMapping("/upload")
public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException {
//获取文件名 : file.getOriginalFilename();
String uploadFileName = file.getOriginalFilename();
//如果文件名为空,直接回到首页!
if ("".equals(uploadFileName)){
return "redirect:/index.jsp";
}
System.out.println("上传文件名 : "+uploadFileName);
//上传路径保存设置
String path = request.getServletContext().getRealPath("/upload");
//如果路径不存在,创建一个
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
System.out.println("上传文件保存地址:"+realPath);
InputStream is = file.getInputStream(); //文件输入流
OutputStream os = Files.newOutputStream(new File(realPath, uploadFileName).toPath()); //文件输出流
//读取写出
int len;
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") CommonsMultipartFile 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";
}
}
下载
下载步骤:
- 设置 response 响应头
- 读取文件 -- InputStream
- 写出文件 -- OutputStream
- 执行操作
- 关闭流 (先开后关)
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{
//要下载的图片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "Linux目录.md";
//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 = Files.newInputStream(file.toPath());
//3、 写出文件--输出流
OutputStream out = response.getOutputStream();
byte[] buff = new byte[1024];
int index;
//4、执行 写出操作
while((index = input.read(buff)) != -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构