本文目录导读:

我来详细说明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伪静态的完整适配方案,根据实际需求选择合适的实现方式。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播