本文目录导读:

我来详细说明Java伪静态的适配方法,从基础配置到最佳实践。
伪静态原理
伪静态是将动态URL(如 article.jsp?id=123)转化为静态URL(如 article/123.html),实现方式主要有两种:
- URL重写(Rewrite):服务器层面转换
- RESTful风格:框架层面实现
Tomcat实现伪静态
1 Tuckey URLRewrite Filter
<!-- pom.xml 依赖 -->
<dependency>
<groupId>org.tuckey</groupId>
<artifactId>urlrewritefilter</artifactId>
<version>4.0.4</version>
</dependency>
web.xml配置:
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
<!-- 配置文件路径 -->
<init-param>
<param-name>confPath</param-name>
<param-value>/WEB-INF/urlrewrite.xml</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
urlrewrite.xml规则示例:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
"http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
<urlrewrite>
<!-- 文章详情页 -->
<rule>
<from>^/article/(\d+)\.html$</from>
<to>/article.jsp?id=$1</to>
</rule>
<!-- 分类页面 -->
<rule>
<from>^/category/(\w+)/page/(\d+)\.html$</from>
<to>/category.jsp?name=$1&page=$2</to>
</rule>
<!-- 用户页面 -->
<rule>
<from>^/user/(\w+)/profile\.html$</from>
<to>/user/profile.jsp?username=$1</to>
</rule>
<!-- 防止静态资源被重写 -->
<rule>
<from>^/(css|js|images|fonts|upload)/.*$</from>
<to last="true">-</to>
</rule>
</urlrewrite>
Spring MVC实现伪静态
1 使用@RequestMapping
@Controller
public class ArticleController {
// 映射 /article/123.html
@RequestMapping("/article/{id}.html")
public String viewArticle(@PathVariable("id") Long id, Model model) {
Article article = articleService.getById(id);
model.addAttribute("article", article);
return "article_detail";
}
// 映射 /category/java/page/1.html
@RequestMapping("/category/{name}/page/{page}.html")
public String categoryPage(@PathVariable("name") String name,
@PathVariable("page") Integer page,
Model model) {
// 处理逻辑
return "category";
}
}
2 配置后缀匹配
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
// 开启后缀模式匹配
configurer.setUseRegisteredSuffixPatternMatch(true);
configurer.setUseSuffixPatternMatch(true);
}
}
3 自定义PathMatch策略
@Configuration
public class CustomWebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
// 自定义路径匹配器
UrlPathHelper pathHelper = new UrlPathHelper();
pathHelper.setRemoveSemicolonContent(true);
pathHelper.setDefaultEncoding("UTF-8");
configurer.setUrlPathHelper(pathHelper);
// 添加自定义后缀
configurer.addPathPrefix("api", c -> true);
}
}
多环境适配方案
1 环境配置文件
# application-dev.yml
server:
servlet:
encoding:
force-response: true
tomcat:
uri-encoding: UTF-8
# application-prod.yml
server:
servlet:
session:
timeout: 1800
tomcat:
additional-tld-skip-patterns: "*.jar"
2 动态配置
@Component
public class UrlRewriteConfig {
@Value("${urlrewrite.enabled:true}")
private boolean enabled;
@Value("${urlrewrite.static-paths:css,js,images}")
private String staticPaths;
@Bean
public FilterRegistrationBean<UrlRewriteFilter> urlRewriteFilter() {
FilterRegistrationBean<UrlRewriteFilter> filter =
new FilterRegistrationBean<>();
if (enabled) {
UrlRewriteFilter rewriteFilter = new UrlRewriteFilter();
filter.setFilter(rewriteFilter);
filter.addUrlPatterns("/*");
// 根据环境加载不同配置文件
String configPath = "/WEB-INF/urlrewrite-" +
System.getProperty("spring.profiles.active") + ".xml";
filter.addInitParameter("confPath", configPath);
}
return filter;
}
}
Nginx反向代理适配
# nginx.conf
server {
listen 80;
server_name www.example.com;
# 静态资源直接访问
location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
# 伪静态规则
location / {
# 文章详情
if ($request_uri ~* "^/article/(\d+)\.html$") {
set $article_id $1;
rewrite ^ /article.jsp?id=$article_id break;
}
# 分类列表
if ($request_uri ~* "^/category/(\w+)/page/(\d+)/?$") {
set $category_name $1;
set $page_num $2;
rewrite ^ /category.jsp?name=$category_name&page=$page_num break;
}
# 转发到Tomcat
proxy_pass http://tomcat_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
拦截器适配实现
@Component
public class PseudoStaticInterceptor implements HandlerInterceptor {
private static final Pattern STATIC_PATTERN =
Pattern.compile(".*\\.(html|htm|shtml)$");
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
String requestURI = request.getRequestURI();
// 检查是否为伪静态请求
if (STATIC_PATTERN.matcher(requestURI).matches()) {
// 解析伪静态URL
Map<String, String> params = parsePseudoStaticUrl(requestURI);
// 设置请求参数
if (params != null && !params.isEmpty()) {
request.setAttribute("pseudoStaticParams", params);
}
}
return true;
}
private Map<String, String> parsePseudoStaticUrl(String url) {
Map<String, String> params = new HashMap<>();
// 示例:/article/123.html
Pattern articlePattern = Pattern.compile("/article/(\\d+)\\.html");
Matcher matcher = articlePattern.matcher(url);
if (matcher.find()) {
params.put("id", matcher.group(1));
params.put("type", "article");
}
return params;
}
}
最佳实践建议
1 统一配置管理
@Component
@ConfigurationProperties(prefix = "pseudo-static")
public class PseudoStaticProperties {
private boolean enabled = true;
private String suffix = ".html";
private Map<String, String> rules = new HashMap<>();
// getters and setters
}
// application.yml
pseudo-static:
enabled: true
suffix: .html
rules:
article: "/article/{id}"
category: "/category/{name}/page/{page}"
user: "/user/{username}/profile"
2 性能优化
@Component
public class PseudoStaticCache {
@Autowired
private CacheManager cacheManager;
public void cacheStaticUrl(String path, Object value) {
Cache cache = cacheManager.getCache("pseudoStatic");
if (cache != null) {
cache.put(path, value);
}
}
public Object getFromCache(String path) {
Cache cache = cacheManager.getCache("pseudoStatic");
if (cache != null) {
Cache.ValueWrapper wrapper = cache.get(path);
return wrapper != null ? wrapper.get() : null;
}
return null;
}
}
3 测试用例
@SpringBootTest
@AutoConfigureMockMvc
public class PseudoStaticTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testArticleStaticUrl() throws Exception {
mockMvc.perform(get("/article/123.html")
.accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(view().name("article_detail"))
.andExpect(model().attributeExists("article"));
}
@Test
public void testCategoryPagination() throws Exception {
mockMvc.perform(get("/category/java/page/2.html")
.accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(view().name("category"));
}
@Test
public void testInvalidUrl() throws Exception {
mockMvc.perform(get("/invalid/url.html")
.accept(MediaType.TEXT_HTML))
.andExpect(status().isNotFound());
}
}
注意事项
- URL规范化:统一使用小写字母,避免大小写问题
- SEO优化:保持URL语义化,包含关键词
- 安全性:防止路径遍历攻击,验证参数合法性
- 兼容性:注意不同容器的配置差异
- 调试工具:使用浏览器开发者工具监控URL请求
是Java伪静态的完整适配方案,根据实际需求选择合适的实现方式。