Java 如何在 Spring MVC 中将请求映射到 HTML 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16598594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to map requests to HTML file in Spring MVC?
提问by Suzan Cioc
Basic configuration files looks unintuitive.
基本配置文件看起来不直观。
If I create simple hello world example, and then rename home.jsp
to home.html
and edit servlet-context.xml
file from
如果我创建简单的Hello World例子,然后重命名home.jsp
,以home.html
和编辑servlet-context.xml
从文件
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
to
到
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".html" />
</beans:bean>
I start to get an error
我开始出错
WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/myapp/WEB-INF/views/home.html] in DispatcherServlet with name 'appServlet'
Why? What suffix
property means?
为什么?suffix
财产是什么意思?
UPDATE
更新
My controller is follows. As you see it does not contain file extension
我的控制器如下。如您所见,它不包含文件扩展名
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
return "home";
}
}
回答by Indu Devanath
I think the InternalResourceViewResolversupports servlets and jsp files. Suffix as per Spring's API javadocs is that which "gets appended to view names when building a URL". It is not the file's extension, even though it is very misleading. I checked on UrlBasedViewResolver setSuffix()class.
我认为InternalResourceViewResolver支持 servlet 和 jsp 文件。根据 Spring 的 API javadocs 后缀是“在构建 URL 时附加到视图名称”。它不是文件的扩展名,即使它非常具有误导性。我检查了UrlBasedViewResolver setSuffix()类。
Probably if they name it as viewSuffix, it might make more sense, I guess.
可能如果他们将其命名为 viewSuffix,我猜可能会更有意义。
回答by Megan Nguyen
Resolver class is used to resolve resources of a view class, view class in turn, generates the views from resources. For example, with a typical InternalResourceViewResolver as below:
解析器类用于解析视图类的资源,视图类依次从资源生成视图。例如,典型的 InternalResourceViewResolver 如下:
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
A view name "home" will be mapped as "/WEB-INT/views/home.jsp" and then translated into a JSP view using view class InternalResourceView (which is for JSP). If you replace the suffix value with ".html", Spring can get the specific resource "/WEB-INT/views/home.html" but doesn't know how to generate it.
视图名称“home”将被映射为“/WEB-INT/views/home.jsp”,然后使用视图类InternalResourceView(用于JSP)转换为JSP 视图。如果将后缀值替换为“.html”,Spring 可以获得特定资源“/WEB-INT/views/home.html”但不知道如何生成它。
回答by Jonas
回答by gnc
Spring MVC doesn't allow you to render static resources over controllers. As Arun said, it should be served through resources
.
Spring MVC 不允许您通过控制器呈现静态资源。正如阿伦所说,它应该通过resources
.
Correct me if I'm wrong, but it seems you want an index.html
as a front page. To achieve this you should have a Controller (say IndexController) mapped to /index.html
. Then, you should configure in your web.xml
your yo say that your welcome-file is index.html
. This way, whenever you point to the root of your application, your container will look for a "/index.html" and in turn, will look for the Controller mapped to the /index.html
URL.
如果我错了,请纠正我,但您似乎想要一个index.html
作为头版。要实现这一点,您应该将控制器(例如 IndexController)映射到/index.html
. 然后,你应该在你web.xml
的 yo 中配置你的欢迎文件是index.html
. 这样,每当您指向应用程序的根目录时,您的容器都会查找“/index.html”,然后查找映射到/index.html
URL的控制器。
So, your controller should look something like this:
所以,你的控制器应该是这样的:
@Controller
@RequestMapping("/index.html")
public class MyIndexController {
@RequestMapping(method=RequestMethod.GET)
protected String gotoIndex(Model model) throws Exception {
return "myLandingPage";
}
}
And in your web.xml
在你的 web.xml 中
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
Hope this helps.
希望这可以帮助。
回答by longkai
well, it seems you didn' t set the view' s order.
好吧,看来您没有设置视图的顺序。
for example, if your project has view like jsp, json, velocity, freemarker, etc. you can use all of them(maybe you need new version of spring, 3.1+), but only one view will be select to renderto client, that depends on your view' s order, the lower the order, the prefer the view.
例如,如果您的项目有 jsp、json、velocity、freemarker 等视图,您可以使用所有视图(可能您需要新版本的 spring,3.1+),但只会选择一个视图来呈现给客户端,这取决于您的视图的顺序,顺序越低,越喜欢视图。
for example, you set jspview' s order is 1, and freemarker view' s order is 2, both of their view name is "home", the spring will choose view.jsp(if you set suffix to .jsp). Well, if your view name is "index", no index.jsp but index.ftl(suppose you set freemarker' s view to .ftl), spring will choose the later.
例如,你设置jsp视图的顺序是1,freemarker视图的顺序是2,它们的视图名称都是“home”,spring会选择view.jsp(如果你设置后缀为.jsp)。好吧,如果您的视图名称是“index”,没有 index.jsp 而是 index.ftl(假设您将 freemarker 的视图设置为 .ftl),那么 spring 会选择后者。
the sample code using spring' s java config, you can easily convert to xml-style.
示例代码使用 spring 的 java 配置,可以轻松转换为 xml 样式。
@Bean
public InternalResourceViewResolver jspViewResolver() {
InternalResourceViewResolver jsp = new InternalResourceViewResolver();
jsp.setOrder(4);
jsp.setCache(true);
jsp.setViewClass(org.springframework.web.servlet.view.JstlView.class);
jsp.setPrefix("/WEB-INF/jsp/");
jsp.setSuffix(".jsp");
return jsp;
}
@Bean
public FreeMarkerViewResolver freeMarkerViewResolver() {
FreeMarkerViewResolver viewResolver = new FreeMarkerViewResolver();
viewResolver.setCache(true);
viewResolver.setPrefix("");
viewResolver.setSuffix(".ftl");
viewResolver.setContentType(ViewConstants.MEDIA_TYPE_HTML);
viewResolver.setRequestContextAttribute("request");
viewResolver.setExposeSpringMacroHelpers(true);
viewResolver.setExposeRequestAttributes(true);
viewResolver.setExposeSessionAttributes(true);
viewResolver.setOrder(2);
return viewResolver;
}
please see the setOrder()method!
请参阅setOrder()方法!
the json, jsonp and other type of views may use ontentNegotiation, and you can find it on spring' s docs.
json、jsonp 和其他类型的视图可能会使用 ontentNegotiation,您可以在 spring 的文档中找到它。
finally, the html view, I mean, totally static files, which is not support by spring default. I suppose the static file desn' t need render by java. you can use the static mapping using the code below:
最后,html 视图,我的意思是,完全静态文件,spring 默认不支持。我想静态文件不需要由 java 渲染。您可以使用以下代码使用静态映射:
<mvc:resources mapping="/static/**" location="/static/" />
or use java config:
或使用 java 配置:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
int cachePeriod = 3600 * 24 * 15;
registry.addResourceHandler("/static/**").addResourceLocations("/static/").setCachePeriod(cachePeriod);
registry.addResourceHandler("/favicon.ico").addResourceLocations("/").setCachePeriod(cachePeriod);
registry.addResourceHandler("/robots.txt").addResourceLocations("/").setCachePeriod(cachePeriod);
}
and in your @RequestMapping method, you should redirectit!
在你的@RequestMapping 方法中,你应该重定向它!
well, if you don' t want redirection, just set the html view to an dynamicview (freemark, velecity, etc), which will be ok!
好吧,如果您不想重定向,只需将 html 视图设置为动态视图(freemark、velecity 等),就可以了!
hope it useful!
希望有用!
回答by Renganathan V
You have this problem because there might not be any servlet registered for mapping *.html.
so the call ends up with the "default servlet", which is registered with a servlet-mapping of / which probably your DispatcherServlet is.
Now the Dispatcher servlet does not find a controller to handle request for home.html and hence the message that you are seeing.
To solve this problem you can register *.html extension to be handled by JSPServlet and then it should work cleanly.
您遇到此问题是因为可能没有为映射 *.html 注册任何 servlet。
所以调用以“默认 servlet”结束,它用 / 的 servlet 映射注册,这可能是您的 DispatcherServlet 。
现在 Dispatcher servlet 没有找到处理 home.html 请求的控制器,因此没有找到您所看到的消息。
要解决这个问题,您可以注册 *.html 扩展名以由 JSPServlet 处理,然后它应该可以正常工作。
回答by walkeros
Background of the problem
问题背景
First thing to understand is following: it is NOT spring which renders the jsp files. It is JspServlet (org.apache.jasper.servlet.JspServlet) which does it. This servlet comes with Tomcat (jasper compiler) not with spring. This JspServlet is aware how to compile jsp page and how to return it as html text to the client. The JspServlet in tomcat by default only handles requests matching two patterns: *.jsp and *.jspx.
首先要理解的是:呈现jsp文件的不是spring。它是 JspServlet (org.apache.jasper.servlet.JspServlet) 做的。这个 servlet 带有 Tomcat(jasper 编译器)而不是 spring。这个 JspServlet 知道如何编译 jsp 页面以及如何将它作为 html 文本返回给客户端。tomcat 中的 JspServlet 默认只处理匹配两种模式的请求:*.jsp 和 *.jspx。
Now when spring renders the view with InternalResourceView
(or JstlView
), three things really takes place:
现在,当 spring 使用InternalResourceView
(or JstlView
)渲染视图时,真正发生了三件事:
- get all the model parameters from model (returned by your controller handler method i.e.
"public ModelAndView doSomething() { return new ModelAndView("home") }"
) - expose these model parameters as request attributes (so that it can be read by JspServlet)
- forward request to JspServlet.
RequestDispatcher
knows that each *.jsp request should be forwarded to JspServlet (because this is default tomcat's configuration)
- 从模型中获取所有模型参数(由您的控制器处理程序方法即返回
"public ModelAndView doSomething() { return new ModelAndView("home") }"
) - 将这些模型参数作为请求属性公开(以便它可以被 JspServlet 读取)
- 将请求转发到 JspServlet。
RequestDispatcher
知道每个*.jsp请求都应该转发到JspServlet(因为这是tomcat的默认配置)
When you simply change the view name to home.html tomcat will notknow how to handle the request. This is because there is no servlet handling *.html requests.
当您简单地将视图名称更改为 home.html 时,tomcat 将不知道如何处理请求。这是因为没有 servlet 处理 *.html 请求。
Solution
解决方案
How to solve this. There are three most obvious solutions:
如何解决这个问题。最明显的解决方案有以下三种:
- expose the html as a resource file
- instruct the JspServlet to also handle *.html requests
- write your own servlet (or pass to another existing servlet requests to *.html).
- 将 html 公开为资源文件
- 指示 JspServlet 也处理 *.html 请求
- 编写您自己的 servlet(或将另一个现有的 servlet 请求传递给 *.html)。
Initial configuration(only handling jsp)
初始配置(只处理jsp)
First let's assume we configure spring without xml files (only basing on @Configuration annotation and spring's WebApplicationInitializer interface).
首先假设我们在没有xml文件的情况下配置spring(仅基于@Configuration注解和spring的WebApplicationInitializer接口)。
Basic configuration would be following
基本配置如下
public class MyWebApplicationContext extends AnnotationConfigWebApplicationContext {
private static final String CONFIG_FILES_LOCATION = "my.application.root.config";
public MyWebApplicationContext() {
super();
setConfigLocation(CONFIG_FILES_LOCATION);
}
}
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = new MyWebApplicationContext();
servletContext.addListener(new ContextLoaderListener(context));
addSpringDispatcherServlet(servletContext, context);
}
private void addSpringDispatcherServlet(ServletContext servletContext, WebApplicationContext context) {
ServletRegistration.Dynamic dispatcher = servletContext.addServlet("DispatcherServlet",
new DispatcherServlet(context));
dispatcher.setLoadOnStartup(2);
dispatcher.addMapping("/");
dispatcher.setInitParameter("throwExceptionIfNoHandlerFound", "true");
}
}
package my.application.root.config
// (...)
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
@Qualifier("jstlViewResolver")
private ViewResolver jstlViewResolver;
@Bean
@DependsOn({ "jstlViewResolver" })
public ViewResolver viewResolver() {
return jstlViewResolver;
}
@Bean(name = "jstlViewResolver")
public ViewResolver jstlViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("/WEB-INF/internal/");
resolver.setViewClass(JstlView.class);
resolver.setSuffix(".jsp");
return resolver;
}
}
In above example I'm using UrlBasedViewResolver with backing view class JstlView, but you can use InternalResourceViewResolver as in your example it does not matter.
在上面的示例中,我将 UrlBasedViewResolver 与支持视图类 JstlView 一起使用,但是您可以像在示例中一样使用 InternalResourceViewResolver,这无关紧要。
Above example configures application with only one view resolver which handles jsp files ending with .jsp
. NOTE: As stated in the beginning JstlView really uses tomcat's RequestDispatcher to forward the request to JspSevlet to compile the jsp to html.
上面的示例仅使用一个视图解析器配置应用程序,该解析器处理以 .jsp 结尾的 jsp 文件.jsp
。注意:正如开头所说,JstlView 确实使用了tomcat 的RequestDispatcher 将请求转发到JspSevlet 以将jsp 编译为html。
Implementation on solution 1- expose the html as a resource file:
解决方案 1 的实现- 将 html 公开为资源文件:
We modify the WebConfig class to add new resources matching. Also we need to modify the jstlViewResolver so that it does not take neither prefix nor suffix:
我们修改 WebConfig 类以添加新的资源匹配。我们还需要修改 jstlViewResolver 使其既不带前缀也不带后缀:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
@Qualifier("jstlViewResolver")
private ViewResolver jstlViewResolver;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/someurl/resources/**").addResourceLocations("/resources/");
}
@Bean
@DependsOn({ "jstlViewResolver" })
public ViewResolver viewResolver() {
return jstlViewResolver;
}
@Bean(name = "jstlViewResolver")
public ViewResolver jstlViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix(""); // NOTE: no prefix here
resolver.setViewClass(JstlView.class);
resolver.setSuffix(""); // NOTE: no suffix here
return resolver;
}
// NOTE: you can use InternalResourceViewResolver it does not matter
// @Bean(name = "internalResolver")
// public ViewResolver internalViewResolver() {
// InternalResourceViewResolver resolver = new InternalResourceViewResolver();
// resolver.setPrefix("");
// resolver.setSuffix("");
// return resolver;
// }
}
By adding this we say that every that every request going to http://my.server/someurl/resources/is mapped to resources directory under your web directory. So if you put your home.html in resources directory and point your browser to http://my.server/someurl/resources/home.htmlthe file will be served. To handle this by your controller you then return the full path to the resource:
通过添加这个,我们说每个去http://my.server/someurl/resources/ 的请求都映射到你的 web 目录下的资源目录。因此,如果您将 home.html 放在资源目录中,并将浏览器指向http://my.server/someurl/resources/home.html,则会提供该文件。要由您的控制器处理此问题,您可以返回资源的完整路径:
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home(Locale locale, Model model) {
// (...)
return new ModelAndView("/someurl/resources/home.html"); // NOTE here there is /someurl/resources
}
}
If you place in the same directory some jsp files (not only *.html files), say home_dynamic.jsp in the same resources directory you can access it similar way, but you need to use the actual path on the server. The path does notstart with /someurl/ because this is the mapping only for html resources ending with .html). In this context jsp is dynamic resource which in the end is accessed by JspServlet using actual path on disk. So correct way to access the jsp is:
如果你把一些jsp文件(不仅仅是*.html文件)放在同一个目录下,比如说home_dynamic.jsp放在同一个资源目录中,你可以用类似的方式访问它,但你需要使用服务器上的实际路径。的路径中不能与/ someurl /因为这是仅适用于.html结尾的HTML资源)的映射开始。在这种情况下,jsp 是动态资源,最终由 JspServlet 使用磁盘上的实际路径访问。所以访问jsp的正确方法是:
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home(Locale locale, Model model) {
// (...)
return new ModelAndView("/resources/home_dynamic.jsp"); // NOTE here there is /resources (there is no /someurl/ because "someurl" is only for static resources
}
To achieve this in xml based config you need to use:
要在基于 xml 的配置中实现这一点,您需要使用:
<mvc:resources mapping="/someurl/resources/**" location="/resources/" />
and modify your jstl view resolver:
并修改您的 jstl 视图解析器:
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- Please NOTE that it does not matter if you use InternalResourceViewResolver or UrlBasedViewResolver as in annotations example -->
<beans:property name="prefix" value="" />
<beans:property name="suffix" value="" />
</beans:bean>
Implementation on solution 2:
解决方案2的实施:
In this option we use the tomcat's JspServlet to handle also static files. As a consequence you can use jsp tags in your html files:) It's of course your choice if you do it or not. Most probably you want to use plain html so simply do not use jsp tags and the content will be served as if it was static html.
在这个选项中,我们使用 tomcat 的 JspServlet 来处理静态文件。因此,您可以在您的 html 文件中使用 jsp 标签:) 当然,您是否这样做是您的选择。很可能您想使用纯 html,所以不要使用 jsp 标签,内容将被视为静态 html。
First we delete prefix and suffix for view resolver as in previous example:
首先,我们删除视图解析器的前缀和后缀,如上例所示:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
@Qualifier("jstlViewResolver")
private ViewResolver jstlViewResolver;
@Bean
@DependsOn({ "jstlViewResolver" })
public ViewResolver viewResolver() {
return jstlViewResolver;
}
@Bean(name = "jstlViewResolver")
public ViewResolver jstlViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver(); // NOTE: this time I'm using InternalResourceViewResolver and again it does not matter :)
resolver.setPrefix("");
resolver.setSuffix("");
return resolver;
}
}
Now we add JspServlet for handling also *.html files:
现在我们添加 JspServlet 来处理 *.html 文件:
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = new MyWebApplicationContext();
servletContext.addListener(new ContextLoaderListener(context));
addStaticHtmlFilesHandlingServlet(servletContext);
addSpringDispatcherServlet(servletContext, context);
}
// (...)
private void addStaticHtmlFilesHandlingServlet(ServletContext servletContext) {
ServletRegistration.Dynamic servlet = servletContext.addServlet("HtmlsServlet", new JspServlet()); // org.apache.jasper.servlet.JspServlet
servlet.setLoadOnStartup(1);
servlet.addMapping("*.html");
}
}
Important is that to make this class available you need to add the jasper.jar from your tomcat's installation just for compilation time. If you have maven app this is realtively easy by using the scope=provided for the jar. The dependency in maven will look like:
重要的是,要使这个类可用,您需要从 tomcat 的安装中添加 jasper.jar,仅用于编译时间。如果你有 maven 应用程序,这真的很容易通过使用为 jar 提供的 scope=provided。Maven 中的依赖项如下所示:
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>${tomcat.libs.version}</version>
<scope>provided</scope> <!--- NOTE: scope provided! -->
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jsp-api</artifactId>
<version>${tomcat.libs.version}</version>
<scope>provided</scope>
</dependency>
If you want to do it in xml way. You would need to register jsp servlet to handle *.html requests, so you need to add following entry to your web.xml
如果你想以xml方式进行。您需要注册 jsp servlet 来处理 *.html 请求,因此您需要将以下条目添加到您的 web.xml
<servlet>
<servlet-name>htmlServlet</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>htmlServlet</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
Now in your controller you can access both html and jsp files just like in previous example. The advantage is that there is no "/someurl/" extra mapping which was needed in Solution 1. Your controller will look like:
现在在您的控制器中,您可以像前面的示例一样访问 html 和 jsp 文件。优点是没有解决方案 1 中所需的“/someurl/”额外映射。您的控制器将如下所示:
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home(Locale locale, Model model) {
// (...)
return new ModelAndView("/resources/home.html");
}
To point to your jsp you are doing exactly the same:
要指向您的 jsp,您正在做完全相同的事情:
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home(Locale locale, Model model) {
// (...)
return new ModelAndView("/resources/home_dynamic.jsp");
}
Implementation on solution 3:
解决方案3的实施:
Third solution is somewhat a combination of solution 1 and solution 2. So in here we want to pass all the requests to *.html to some other servlet. You can write your own or look for some good candidate of already existing servlet.
第三个解决方案有点像解决方案 1 和解决方案 2 的组合。所以在这里我们希望将所有对 *.html 的请求传递给其他一些 servlet。您可以编写自己的或寻找现有 servlet 的一些好的候选者。
As above first we clean up the prefix and suffix for the view resolver:
如上所述,首先我们清理视图解析器的前缀和后缀:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
@Qualifier("jstlViewResolver")
private ViewResolver jstlViewResolver;
@Bean
@DependsOn({ "jstlViewResolver" })
public ViewResolver viewResolver() {
return jstlViewResolver;
}
@Bean(name = "jstlViewResolver")
public ViewResolver jstlViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver(); // NOTE: this time I'm using InternalResourceViewResolver and again it does not matter :)
resolver.setPrefix("");
resolver.setSuffix("");
return resolver;
}
}
Now instead of using the tomcat's JspServlet we write our own servlet (or reuse some existing):
现在我们不再使用 tomcat 的 JspServlet,而是编写我们自己的 servlet(或重用一些现有的):
public class StaticFilesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");
String resourcePath = request.getRequestURI();
if (resourcePath != null) {
FileReader reader = null;
try {
URL fileResourceUrl = request.getServletContext().getResource(resourcePath);
String filePath = fileResourceUrl.getPath();
if (!new File(filePath).exists()) {
throw new IllegalArgumentException("Resource can not be found: " + filePath);
}
reader = new FileReader(filePath);
int c = 0;
while (c != -1) {
c = reader.read();
if (c != -1) {
response.getWriter().write(c);
}
}
} finally {
if (reader != null) {
reader.close();
}
}
}
}
}
We now instruct the spring to pass all requests to *.html to our servlet
我们现在指示 spring 将所有对 *.html 的请求传递给我们的 servlet
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
WebApplicationContext context = new MyWebApplicationContext();
servletContext.addListener(new ContextLoaderListener(context));
addStaticHtmlFilesHandlingServlet(servletContext);
addSpringDispatcherServlet(servletContext, context);
}
// (...)
private void addStaticHtmlFilesHandlingServlet(ServletContext servletContext) {
ServletRegistration.Dynamic servlet = servletContext.addServlet("HtmlsServlet", new StaticFilesServlet());
servlet.setLoadOnStartup(1);
servlet.addMapping("*.html");
}
}
The advantage (or disadvantage, depends on what you want) is that jsp tags will obviously not be processed. You controller looks as usual:
优点(或缺点,取决于你想要什么)是 jsp 标签显然不会被处理。您的控制器看起来像往常一样:
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home(Locale locale, Model model) {
// (...)
return new ModelAndView("/resources/home.html");
}
And for jsp:
而对于jsp:
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView home(Locale locale, Model model) {
// (...)
return new ModelAndView("/resources/home_dynamic.jsp");
}