Servlet 原生API
# Servlet 原生API
前言
在 Spring Boot 中,尽管它提供了高层次的封装和简化,但仍然保留了对原生 Servlet API 的支持。Spring Boot 应用中,很多场景下仍然需要使用到 Servlet 的原生功能,比如 HttpServletRequest
、HttpServletResponse
、HttpSession
等。
# 一、Spring Boot如何调用Servlet API
# 1. 在 Controller 层使用 Servlet API
在 Controller 层,Servlet API 作为方法参数直接注入,Spring 会自动将当前请求的对象传递给控制器方法。
@RestController
@RequestMapping("/api")
public class MyController {
@GetMapping("/example")
public String handleRequest(HttpServletRequest request, HttpServletResponse response, HttpSession session) {
// 在 Controller 层,直接使用这些对象
return "请求处理成功";
}
}
2
3
4
5
6
7
8
9
10
关键点:
- 方法参数注入:在 Controller 方法中,
HttpServletRequest
、HttpServletResponse
和HttpSession
可以作为方法参数直接注入。 - Spring 自动注入:这些对象由 Spring 自动注入,与当前请求相关联。
# 2. 在 Service 层使用 Servlet API
通过依赖注入,可以在 Service 层中直接获取 Servlet API 对象,通常用于获取请求信息或设置全局响应数据。
使用 @Autowired
注入
@Service
public class UserService {
@Autowired
private HttpServletRequest request;
@Autowired
private HttpSession session;
public void performAction() {
// 在 Service 层使用 HttpServletRequest 和 HttpSession
}
}
2
3
4
5
6
7
8
9
10
11
12
13
关键点:
- 依赖注入:使用
@Autowired
注入 Servlet API 对象,适用于 Spring 管理的任何 Bean。 - 线程安全:Spring 为每个请求创建独立的
HttpServletRequest
和HttpSession
,确保线程安全。
# 3. 在工具类中使用 Servlet API
在工具类中,由于无法直接注入 HttpServletRequest
和 HttpServletResponse
,可以通过 Spring 提供的 RequestContextHolder
来获取这些对象。
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.stereotype.Component;
@Component
public class ServletUtil {
public static HttpServletRequest getRequest() {
// 获取当前请求的 HttpServletRequest
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
public static HttpServletResponse getResponse() {
// 获取当前请求的 HttpServletResponse
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
关键点:
RequestContextHolder
:用于获取当前请求的上下文,可在任意 Spring Bean 中使用。- 为什么需要强换:
RequestContextHolder.getRequestAttributes()
返回的类型是RequestAttributes
,而获取请求和响应的方法只有在ServletRequestAttributes
中可用,因此需要强制转换。 - 适用场景:在工具类中统一处理请求和响应数据,如日志记录、通用的参数处理等。
# 二、Servlet API 的使用
HttpServletRequest 和 HttpServletResponse
- 这些对象代表了当前请求的 HTTP 请求和响应,生命周期与这次请求相同。当一个请求到达服务器时,Spring 会为该请求生成对应的
HttpServletRequest
和HttpServletResponse
对象,并在请求处理完毕后销毁。 - 不管您在哪个层次(Controller、Service、工具类等)使用它们,它们始终指向当前请求对应的对象。
# 1. HttpServletRequest
的使用
HttpServletRequest
是一个重要的接口,提供了对请求数据的访问。可以获取请求参数、请求头、请求路径、Cookie、Session 等信息。
使用示例:
import javax.servlet.http.HttpServletRequest;
@RestController
@RequestMapping("/api")
public class RequestController {
@GetMapping("/request-info")
public String getRequestInfo(HttpServletRequest request) {
// 1. 获取请求方法,如 GET、POST
String method = request.getMethod();
// 2. 获取请求的完整 URL,不包含查询参数
String requestURL = request.getRequestURL().toString();
// 3. 获取查询参数部分,例如 ?name=John&age=30
String queryString = request.getQueryString();
// 4. 获取指定的请求头信息,例如 User-Agent
String userAgent = request.getHeader("User-Agent");
// 5. 获取客户端的 IP 地址
String clientIp = request.getRemoteAddr();
// 6. 获取请求中的单个参数值
String username = request.getParameter("username");
// 7. 获取多个同名参数的值,返回数组
String[] interests = request.getParameterValues("interests");
// 8. 获取所有请求参数的 Map
Map<String, String[]> paramMap = request.getParameterMap();
// 9. 获取与当前请求关联的 HttpSession 对象,用于在多个请求之间共享数据
HttpSession session = request.getSession();
return String.format(
"请求方法: %s\n请求URL: %s\n查询参数: %s\nUser-Agent: %s\n客户端IP: %s\n用户名: %s\n兴趣: %s",
method, requestURL, queryString, userAgent, clientIp, username,
interests != null ? String.join(", ", interests) : "无"
);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
关键点说明:
request.getMethod()
:获取 HTTP 请求方法(如 GET、POST)。request.getRequestURL()
:获取请求的完整 URL。request.getQueryString()
:获取请求的查询参数部分。request.getHeader("User-Agent")
:获取指定的请求头信息。request.getRemoteAddr()
:获取客户端的 IP 地址。request.getParameter("paramName")
:获取请求中的单个参数值。request.getParameterValues("paramName")
:获取多个同名参数的值,返回数组。request.getParameterMap()
:获取所有请求参数的 Map。request.getSession()
:获取与当前请求关联的会话对象,用于在多个请求之间共享数据。
# 2. HttpServletResponse
的使用
HttpServletResponse
用于设置响应数据,如响应状态码、响应头、Cookie、输出流等。
使用示例:
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
@RequestMapping("/api")
public class ResponseController {
@GetMapping("/custom-response")
public void setCustomResponse(HttpServletResponse response) {
try {
// 1. 设置 HTTP 响应状态码,例如 200 OK
response.setStatus(HttpServletResponse.SC_OK);
// 2. 设置自定义响应头,例如 "Custom-Header: CustomValue"
response.setHeader("Custom-Header", "CustomValue");
// 3. 设置响应的内容类型和字符编码
response.setContentType("application/json;charset=UTF-8");
// 4. 获取输出流并写入 JSON 数据到响应体中
response.getWriter().write("{\"message\":\"自定义响应内容\"}");
// 5. 刷新输出流,确保数据完全发送到客户端
response.getWriter().flush();
// 6. 添加一个 Cookie 到响应中
Cookie cookie = new Cookie("sessionId", "12345");
cookie.setMaxAge(60 * 60); // 设置 Cookie 的有效期为 1 小时
response.addCookie(cookie);
// 7. 如果需要,执行重定向操作
// response.sendRedirect("/login");
} catch (IOException e) {
e.printStackTrace();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
关键点说明:
response.setStatus(HttpServletResponse.SC_OK)
:设置 HTTP 响应状态码(如 200 OK)。response.setHeader("Custom-Header", "CustomValue")
:设置自定义响应头。response.setContentType("application/json;charset=UTF-8")
:设置响应的内容类型和字符编码。response.getWriter().write()
:向响应体中写入数据。response.getWriter().flush()
:刷新输出流,确保数据完全发送到客户端。response.addCookie(cookie)
:向响应中添加一个 Cookie。response.sendRedirect("/login")
:执行重定向操作。
# 3. HttpSession
的使用
HttpSession
用于在多个请求之间保存用户的数据,如登录状态、购物车等。
提示
HttpSession
是基于会话的对象,它的生命周期通常比单个请求要长,意味着可以在多个请求之间共享数据(例如用户的登录状态、购物车信息等)。当用户第一次访问应用时,服务器会为该用户创建一个新的会话,并分配一个唯一的会话 ID。这个会话 ID 会通过 Cookie 或 URL 参数的形式传递,确保在同一个会话期间,用户的多次请求都关联到同一个 HttpSession
对象。
会话有效期:HttpSession
的默认过期时间(或称超时时间)通常是 30 分钟(即 1800 秒),可以通过配置文件或编程方式进行调整。如果在这个时间段内用户没有进行任何操作(没有新的请求),会话就会失效。
会话过期后:一旦会话过期,HttpSession
中保存的数据(如用户信息、购物车等)将被清除。用户下一次发起请求时,会创建一个新的会话,且之前的数据不再可用。
使用示例:判断用户是否登录
当用户登录成功后,服务器会将用户的一些关键信息(如用户名、用户 ID 等)存储在 HttpSession
中,作为用户已登录的标志。在之后的请求中,服务器会先检查 HttpSession
中是否存在这些信息。如果能够取出这些信息,说明用户已经登录,可以正常处理请求;如果无法取出,说明用户未登录或会话已失效,需要用户重新登录。
@RestController
@RequestMapping("/api")
public class SessionController {
/**
* 使用 HttpSession 保存和获取会话数据
* @param session HttpSession 对象,必须传入以便操作会话数据
* @return 响应信息
*/
@GetMapping("/set-session")
public String setSession(HttpSession session) {
// 设置会话属性
session.setAttribute("username", "JohnDoe");
return "Session data set";
}
@GetMapping("/get-session")
public String getSession(HttpSession session) {
// 获取会话属性
String username = (String) session.getAttribute("username");
if (username == null) {
return "No session data found";
}
return "Session data: " + username;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
关键点:
session.setAttribute("key", value)
:设置会话属性。session.getAttribute("key")
:获取会话属性。
# 3.1 配置会话超时时间
你可以通过在 Spring Boot 的配置文件中调整会话的超时时间,例如:
在 application.properties
中配置:
server.servlet.session.timeout=20m # 设置会话超时时间为 20 分钟
在 application.yml
中配置:
server:
servlet:
session:
timeout: 20m # 设置会话超时时间为 20 分钟
2
3
4
你也可以在代码中动态设置会话的超时时间:
@RequestMapping("/set-session-timeout")
public String setSessionTimeout(HttpSession session) {
session.setMaxInactiveInterval(1200); // 设置会话超时时间为 1200 秒(20 分钟)
return "Session timeout set to 20 minutes";
}
2
3
4
5
# 3.2 session自动验证流程
提示
HttpSession session
是当前用户的会话:当服务器验证 JSESSIONID
成功后,服务器会将这个 JSESSIONID
对应的 HttpSession
对象提供给当前请求。此时,你在控制器方法中使用的 HttpSession session
就是当前用户的会话对象,包含该用户的会话数据。
::
第一次登录时创建 Session:
- 当用户第一次登录时,服务器会为该用户创建一个新的
HttpSession
对象,并生成一个唯一的Session ID
。这个Session ID
会通过Set-Cookie
响应头返回给客户端,通常以JSESSIONID
为键名。 - 浏览器会将这个
Session ID
保存到Cookie
中。
示例响应头:
Set-Cookie: JSESSIONID=abc123def456ghi789; Path=/; HttpOnly
1- 当用户第一次登录时,服务器会为该用户创建一个新的
后续请求中自动携带
Session ID
:- 在后续的每次请求中,浏览器会自动在请求头中携带这个
JSESSIONID
,服务器收到请求后会检查这个Session ID
。
示例请求头:
Cookie: JSESSIONID=abc123def456ghi789
1- 在后续的每次请求中,浏览器会自动在请求头中携带这个
服务器验证
Session ID
:- 服务器接收到请求后,会根据
JSESSIONID
查找对应的HttpSession
对象。通过这个HttpSession
对象,服务器可以判断用户是否已登录,并获取会话中存储的数据(如用户信息、权限等)。
如果
JSESSIONID
有效且在服务器的会话存储中存在对应的HttpSession
,则服务器会将请求与该用户的会话关联起来。- 服务器接收到请求后,会根据
会话有效性:
- 如果
Session ID
无效(如会话超时、Session ID
被篡改或伪造),服务器会认为当前请求是一个新的会话,不会将其与之前的登录状态关联。此时,用户可能需要重新登录。
- 如果
注意事项
一个浏览器通常只能为一个应用拥有一个 Session ID
,这意味着同一个浏览器窗口(或标签页)中,无法同时登录同一个应用的多个账号。
# 4. Cookie
的使用
Cookie
可以在客户端保存少量数据,如用户偏好设置、会话标识等。Spring Boot 提供了对 Cookie 的支持,可以方便地读取和设置 Cookie。
使用示例:
@RestController
@RequestMapping("/api")
public class CookieController {
/**
* 设置 Cookie
* @param response HttpServletResponse 对象,必须传入以便设置 Cookie
* @return 响应信息
*/
@GetMapping("/set-cookie")
public String setCookie(HttpServletResponse response) {
// 创建 Cookie 对象
Cookie cookie = new Cookie("userToken", "123456");
cookie.setMaxAge(7 * 24 * 60 * 60); // 设置 Cookie 的有效期为 7 天
cookie.setHttpOnly(true); // 设置 HttpOnly 防止 XSS 攻击
cookie.setPath("/"); // 设置路径
// 将 Cookie 添加到响应中
response.addCookie(cookie);
return "Cookie set successfully";
}
/**
* 获取 Cookie
* @param request HttpServletRequest 对象,必须传入以便获取 Cookie
* @return 响应信息
*/
@GetMapping("/get-cookie")
public String getCookie(HttpServletRequest request) {
// 获取所有的 Cookie
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("userToken".equals(cookie.getName())) {
return "User token: " + cookie.getValue();
}
}
}
return "No user token found";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
关键点:
new Cookie("name", "value")
:创建一个新的 Cookie。response.addCookie(cookie)
:将 Cookie 添加到响应中。request.getCookies()
:获取所有的 Cookie。
# 三、使用 Servlet 过滤器(Filter)
在 Spring Boot 中,还可以通过过滤器来拦截请求和响应,进行一些预处理或后处理,如记录日志、处理跨域请求等。
配置过滤器的示例:
@Component
public class CustomFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 在请求到达 Controller 之前执行
System.out.println("Request URL: " + httpRequest.getRequestURL());
System.out.println("Request Method: " + httpRequest.getMethod());
// 继续执行下一个过滤器或目标资源
chain.doFilter(request, response);
// 在响应返回给客户端之前执行
System.out.println("Response Status: " + httpResponse.getStatus());
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
关键点:
doFilter
方法:doFilter
是过滤器的核心方法,用于拦截请求和响应。chain.doFilter(request, response)
用于继续执行下一个过滤器或目标资源。- 应用场景:过滤器通常用于日志记录、安全验证、请求拦截等场景。
# 四、使用 Servlet 监听器(Listener)
监听器可以监听应用生命周期事件、会话创建与销毁事件、请求的创建与销毁事件等。
配置监听器的示例:
@Component
public class CustomListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("应用启动时执行");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("应用停止时执行");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
关键点:
ServletContextListener
:监听应用启动和销毁事件。contextInitialized
和contextDestroyed
方法:分别在应用启动和停止时执行。
在 Spring Boot 中的拦截器中使用 Servlet API 是一个常见的需求,特别是在需要对请求进行预处理(如权限验证、日志记录等)时。由于拦截器本质上是处理 HTTP 请求的一个切面,所以可以轻松地在其中使用 HttpServletRequest
、HttpServletResponse
等 Servlet API。
# 五、在拦截器中使用 ServletAPI
在 Spring Boot 中,拦截器通常通过实现 HandlerInterceptor
接口来实现。HandlerInterceptor
提供了三个方法:preHandle
、postHandle
和 afterCompletion
,分别用于在请求处理之前、请求处理之后以及请求完成时执行逻辑。在这些方法中可以直接使用 HttpServletRequest
和 HttpServletResponse
。
# 1. 实现拦截器
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在请求处理前进行逻辑处理
System.out.println("拦截器 - 请求路径: " + request.getRequestURI());
System.out.println("拦截器 - 请求方法: " + request.getMethod());
// 例如:检查请求头中的认证信息
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
// 如果认证信息不正确,返回 401 错误
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Unauthorized access");
return false; // 拒绝继续处理请求
}
return true; // 继续处理请求
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, org.springframework.web.servlet.ModelAndView modelAndView) throws Exception {
// 请求处理后但在视图渲染之前执行
System.out.println("拦截器 - 请求处理完成后执行");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 请求完成后执行,通常用于资源清理等操作
System.out.println("拦截器 - 请求完成后执行");
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 2. 注册拦截器
为了让拦截器生效,需要将其注册到 Spring Boot 的拦截器链中,通常通过实现 WebMvcConfigurer
并重写 addInterceptors
方法来实现。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 注册自定义拦截器并指定拦截路径
registry.addInterceptor(myInterceptor)
.addPathPatterns("/api/**") // 拦截 /api/ 下的所有请求
.excludePathPatterns("/api/login"); // 排除某些路径
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
preHandle
:请求处理前执行。这里是使用HttpServletRequest
和HttpServletResponse
的主要方法,可以获取请求路径、请求头、请求参数等信息,并根据需要做出响应。例如,如果发现请求中缺少必要的认证信息,可以直接通过response
返回错误并终止请求处理。postHandle
:请求处理后但在视图渲染之前执行,适合在控制器方法执行后添加一些额外的处理逻辑。afterCompletion
:请求完成后执行,适合用于资源清理或记录日志等操作。
# 五、使用ServletContext
提示
简单来说,ServletContext
就是一个全局容器,它可以在整个 Web 应用的范围内存储和共享数据,供应用的所有组件(如控制器、过滤器、监听器等)使用。在 Spring Boot 项目中,你可以在任意一个文件中获取和设置这些共享数据。
ServletContext
是一个全局范围的对象,在整个 Web 应用中共享。常见的用途包括:
- 在应用范围内共享数据:可以将数据存储在
ServletContext
中,供整个应用程序的所有组件(如 Controllers、Filters、Listeners 等)使用。 - 获取 Web 应用的元数据:如应用的上下文路径、服务器信息、Servlet 版本等。
# 1. 在应用范围内共享数据
ServletContext
允许在整个应用范围内共享数据,例如应用启动时加载的一些配置信息,或者需要在不同组件间共享的全局数据。
代码示例:
@RestController
@RequestMapping("/api")
public class ContextController {
@Autowired
private ServletContext servletContext;
/**
* 设置全局共享数据
*/
@GetMapping("/set-context")
public String setContextData() {
// 将全局数据存储在 ServletContext 中
servletContext.setAttribute("appConfig", "This is a global config data.");
return "Context data set successfully.";
}
/**
* 获取全局共享数据
*/
@GetMapping("/get-context")
public String getContextData() {
// 从 ServletContext 中获取共享数据
String appConfig = (String) servletContext.getAttribute("appConfig");
return appConfig != null ? "Context data: " + appConfig : "No context data found.";
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
关键点:
servletContext.setAttribute("key", value)
:设置应用范围的共享数据,key
为数据标识符,value
为共享数据。servletContext.getAttribute("key")
:获取应用范围的共享数据,通过key
获取存储的数据。- 应用场景:适用于需要在整个应用生命周期内共享的全局配置、数据缓存等,例如全局配置参数、系统状态信息等。
# 2. 获取 Web 应用的元数据
通过 ServletContext
,可以获取应用的元数据信息,例如应用的上下文路径、服务器名称、服务器信息等。这些信息通常用于应用监控、日志记录、版本管理等场景。
代码示例:
@RestController
@RequestMapping("/api")
public class MetadataController {
@Autowired
private ServletContext servletContext;
/**
* 获取应用的元数据信息
*/
@GetMapping("/metadata")
public String getAppMetadata() {
// 获取应用的上下文路径
String contextPath = servletContext.getContextPath();
// 获取服务器信息
String serverInfo = servletContext.getServerInfo();
// 获取 Servlet API 的主版本号和次版本号
int majorVersion = servletContext.getMajorVersion();
int minorVersion = servletContext.getMinorVersion();
return String.format("Context Path: %s, Server Info: %s, Servlet Version: %d.%d",
contextPath, serverInfo, majorVersion, minorVersion);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
关键点:
servletContext.getContextPath()
:获取应用的上下文路径,通常用于生成完整的 URL 或路径映射。servletContext.getServerInfo()
:获取服务器信息,如服务器名称和版本,这在监控和日志中尤为常用。servletContext.getMajorVersion()
和servletContext.getMinorVersion()
:获取当前应用支持的 Servlet API 版本,便于与应用的兼容性进行检查。
# 3. ServletContext
的局限性
尽管 ServletContext
在某些全局数据共享场景下仍然有效,但在 Spring Boot 中,推荐使用更现代化的方式进行全局配置管理和共享数据,例如:
- 使用
@Value
或Environment
读取配置。 - 使用 Spring 的
ApplicationContext
进行全局 Bean 管理。 - 使用 Redis、Ehcache 等缓存工具进行全局数据共享和缓存。
# 六、SpringBoot推荐的写法
在 Spring Boot 项目中,虽然底层仍然是基于 Servlet API 构建的,因此 ServletContext
的这些功能依然可以使用,但在 Spring Boot 提供的更高级和现代化的方案下,通常不建议直接使用这些低层次的 API。以下是具体的情况:
# 1. 获取 Web 应用的真实路径
在 Spring Boot 中,虽然你依然可以使用 ServletContext.getRealPath("/")
获取应用的真实路径,但由于 Spring Boot 的应用通常是打包成 JAR 文件运行,getRealPath
返回的路径可能不是你期望的文件系统路径,而是在 JAR 包内部的路径。因此,这种方式在 Spring Boot 中使用时需要谨慎。
推荐的替代方案:使用 Resource
和 ResourceLoader
来访问资源。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@RestController
public class ResourceController {
@Autowired
private ResourceLoader resourceLoader;
@GetMapping("/load-file")
public String loadFile() {
// 使用 ResourceLoader 来加载资源
Resource resource = resourceLoader.getResource("classpath:static/resource.txt");
try {
if (resource.exists()) {
return "Resource loaded successfully. Path: " + resource.getURI();
} else {
return "Resource not found.";
}
} catch (IOException e) {
return "Error loading resource: " + e.getMessage();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
优势:
- Spring 提供的
Resource
和ResourceLoader
更加灵活,可以处理多种资源类型(如文件系统、类路径、URL 等)。 - 在打包成 JAR 后,仍然可以正确加载资源。
# 2. 加载 Web 应用的资源
在 Spring Boot 项目中,如果你需要加载类路径或其他位置的资源,使用 Spring 提供的 Resource
和 ResourceLoader
是最佳实践。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
@RestController
public class ConfigController {
@Autowired
private ResourceLoader resourceLoader;
@GetMapping("/load-config")
public String loadConfigFile() {
Resource resource = resourceLoader.getResource("classpath:config/my-config.txt");
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
return content.toString();
} catch (IOException e) {
return "Error loading resource: " + e.getMessage();
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 3. 获取应用的初始化参数
在 Spring Boot 中,初始化参数通常通过 application.properties
或 application.yml
文件配置,而不是直接通过 ServletContext
读取。
推荐的替代方案:使用 Spring 的 @Value
或 @ConfigurationProperties
注解读取配置。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ConfigController {
@Value("${configParam:默认值}")
private String configParam;
@GetMapping("/config")
public String getConfig() {
return "Config Param: " + configParam;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
总结
- Spring Boot 更推荐的做法:在 Spring Boot 项目中,推荐使用 Spring 提供的
ResourceLoader
、@Value
、@ConfigurationProperties
等方式来处理资源和配置,而不是直接依赖ServletContext
。 - ServletContext 的适用场景:如果你需要与底层的 Servlet API 进行交互,或者你的项目中有一些遗留代码仍然依赖
ServletContext
,那么这些 API 依然可以使用,但要注意与 Spring Boot 的集成问题。
在现代 Spring Boot 项目中,尽量避免直接使用 ServletContext
进行全局数据的管理或资源加载,而是使用 Spring 提供的更高级、更灵活的解决方案。