Thymeleaf 3内嵌JavaScript中#request对象为null问题解决
#request.requestURL为null的问题 我之前在Spring Boot项目里也碰到过一模一样的情况——片段里#locale能正常获取,但#request.requestURL却报null,折腾了一阵才找到原因,给你几个可行的解决思路:
1. 先排查片段的使用场景
Thymeleaf的#request内置对象只有在完整的Web请求处理链中才会被注入,比如通过Spring MVC的Controller渲染页面时。如果你的这个head-section片段被用到了非Web请求场景(比如异步任务渲染模板、邮件模板生成),此时上下文里并没有HttpServletRequest实例,自然就会报null。
所以第一步先检查:是不是所有引用这个片段的页面,都是通过Controller处理的Web请求来渲染的?如果有非Web场景的引用,那要么避免在这些场景用这个片段,要么给#request加空值判断。
2. 给#request添加空值保护
如果无法避免在某些场景下#request为null,直接在Thymeleaf表达式里加判空逻辑就好,这样不会抛出异常:
<div data-th-fragment="head-section"> <div> blah </div> <script data-th-inline="javascript"> var url = [[${#request != null ? #request.requestURL : ''} ]]; var country = [[${#locale.country}]] </script> </div>
这里用了Thymeleaf的三元表达式,当#request不为null时取requestURL,否则返回空字符串,你也可以根据需求改成其他默认值(比如某个固定URL)。
3. 手动注入Web上下文(如果是手动渲染片段)
如果你是通过TemplateEngine手动渲染这个片段(而不是Spring MVC自动处理),那普通的Context不会包含Web相关对象,需要改用WebContext或者手动传入HttpServletRequest:
方法A:使用WebContext
@Autowired private TemplateEngine templateEngine; @Autowired private HttpServletRequest request; @Autowired private HttpServletResponse response; @Autowired private ServletContext servletContext; public String renderHeadFragment() { // WebContext会自动包含request、response、session等Web对象 WebContext webContext = new WebContext(request, response, servletContext); return templateEngine.process("fragments/head-section", webContext); }
方法B:手动传入request对象
@Autowired private TemplateEngine templateEngine; @Autowired private HttpServletRequest request; public String renderHeadFragment() { Context context = new Context(); // 把request对象放入上下文,Thymeleaf会识别为#request context.setVariable("request", request); return templateEngine.process("fragments/head-section", context); }
4. 改用Controller传递URL(更解耦的方案)
如果你不想依赖Thymeleaf的内置对象#request,可以在Controller里把当前请求URL作为模型属性传递,这样片段里直接取模型变量就行:
Controller代码
@GetMapping("/your-page") public String showYourPage(Model model, HttpServletRequest request) { // 获取完整请求URL并放入模型 model.addAttribute("currentRequestUrl", request.getRequestURL().toString()); return "your-page"; }
片段代码修改
<div data-th-fragment="head-section"> <div> blah </div> <script data-th-inline="javascript"> var url = [[${currentRequestUrl ?: ''} ]]; var country = [[${#locale.country}]] </script> </div>
这种方式更清晰,也降低了模板对Thymeleaf内置对象的依赖,后期维护起来更方便。
最后再确认下:Spring Boot 2.x和Thymeleaf 3.x的版本是兼容的,只要你是用官方starter引入的依赖,版本匹配就没问题,不用额外配置。
内容的提问来源于stack exchange,提问作者ace

