在配置spring mvc mybatis3 mvc 的时候遇到以下问题 总说找不到StandardServletEnvironment 我mvc的包也引进来了

随笔 - 946&
文章 - 1&评论 - 75&trackbacks - 0
从上章里我们已经看到:
& &DispatcherServlet extends FrameworkServlet
& &FrameworkServlet extends HttpServletBean implements ApplicationContextAware
那么HttpServletBean作为DispatcherServlet的父类,起到了一个什么作用呢?
spring中这样描述的:
* Simple extension of {@link javax.servlet.http.HttpServlet} which treats
* its config parameters ({@code init-param} entries within the
* {@code servlet} tag in {@code web.xml}) as bean properties.
* &p&A handy superclass for any type of servlet. Type conversion of config
* parameters is automatic, with the corresponding setter method getting
* invoked with the converted value. It is also possible for subclasses to
* specify required properties. Parameters without matching bean property
* setter will simply be ignored.
* &p&This servlet leaves request handling to subclasses, inheriting the default
* behavior of HttpServlet ({@code doGet}, {@code doPost}, etc).
* &p&This generic servlet base class has no dependency on the Spring
* {@link org.springframework.context.ApplicationContext} concept. Simple
* servlets usually don't load their own context but rather access service
* beans from the Spring root application context, accessible via the
* filter's {@link #getServletContext() ServletContext} (see
* {@link org.springframework.web.context.support.WebApplicationContextUtils}).
* &p&The {@link FrameworkServlet} class is a more specific servlet base
* class which loads its own application context. FrameworkServlet serves
* as direct base class of Spring's full-fledged {@link DispatcherServlet}.*/
我们可以从HttpServletBean的继承关系来分析它的作用:
HttpServletBean extends HttpServlet
implements EnvironmentCapable, EnvironmentAware
1. 继承了javax.servlet.http.HttpServlet
简单的说HttpServletBean是javax.servlet.http.HttpServlet类的简单扩展,在web.xml文件中&servlet&标签的下一级标签中通过&init-param&来配置该servlet的参数。实例如下:
&!-- This servlet must be loaded first to configure the log4j
system and create the WebApplicationContext
&servlet-name&config&/servlet-name&
&servlet-class&org.springframework.framework.web.context.ContextLoaderServlet&/servlet-class&
&init-param&
&param-name&contextClass&/param-name&
&param-value&org.springframework.framework.web.context.XMLWebApplicationContext&/param-value&
&/init-param&
&init-param&
&param-name&log4jPropertiesUrl&/param-name&
&param-value&/WEB-INF/log4j_PRODUCTION.properties&/param-value&
&/init-param&
&!-- This is essential --&
&load-on-startup&1&/load-on-startup&
&/servlet&
& 2. 继承了EnvironmentAware
& &&EnvironmentAware到底起了什么作用呢?这需要我们首先了解一下Aware接口的作用:
* Marker superinterface indicating that a bean is eligible to be
* notified by the Spring container of a particular framework object
* through a callback-style method. Actual method signature is
* determined by individual subinterfaces, but should typically
* consist of just one void-returning method that accepts a single
* argument.
* &p&Note that merely implementing {@link Aware} provides no default
* functionality. Rather, processing must be done explicitly, for example
* in a {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}.
* Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
* and {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}
* for examples of processing {@code *Aware} interface callbacks.
* @author Chris Beams
* @since 3.1
public interface Aware {
容器中定义的Bean一般不需要了解容器的状态或者直接使用容器,但是在某些情况下,是需要在Bean中直接对IOC容器进行操作的,这时候,就需要在Bean中设定对容器的感知。Spring IOC容器也提供了该功能,它是通过特定的Aware接口来完成的。这个比较抽象,我们来从代码来理解吧:
从spring-beans模块中我发现有三个实现了Aware接口,它们分别是:
BeanNameAware:&Interface to be implemented by beans that want to be aware of their&bean name in a bean factory. Note that it is not usually recommended&that an object depend on its bean name, as this represents a potentially&brittle dependence on external configuration, as well as a possibly&unnecessary dependence on a Spring API.
BeanFactoryAware:&Interface to be implemented by beans that wish to be aware of their&owning {@link BeanFactory}.For example, beans can look up collaborating beans via the factory&(Dependency Lookup). Note that most beans will choose to receive references&to collaborating beans via corresponding bean properties or constructor&arguments (Dependency Injection).
BeanClassLoaderAware:&Callback that allows a bean to be aware of the bean&{@link ClassLoader class loader}; that is, the class loader used by the&present bean factory to load bean classes.&This is mainly intended to be implemented by framework classes which&&have to pick up application classes by name despite themselves potentially&being loaded from a shared class loader.
上面三个接口分别实现了响应的set方法:
public interface BeanNameAware extends Aware {
void setBeanName(String name);
public interface BeanFactoryAware extends Aware {
void setBeanFactory(BeanFactory beanFactory) throws BeansE
public interface BeanClassLoaderAware extends Aware {
void setBeanClassLoader(ClassLoader classLoader);
从上述三个例子中,我们可以看到实现了Aware接口,bean就可以在spring容器中使用相应的对象。
那么我们来详细分析一个EnvironmentAware接口:
* Interface to be implemented by any bean that wishes to be notified
* of the {@link Environment} that it runs in.
* @author Chris Beams
* @since 3.1
public interface EnvironmentAware extends Aware {
* Set the {@code Environment} that this object runs in.
void setEnvironment(Environment environment);
我们来看一下HttpServletBean下的setEnvironment方法实现。
* {@inheritDoc}
* @throws IllegalArgumentException if environment is not assignable to
* {@code ConfigurableEnvironment}.
public void setEnvironment(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
this.environment = (ConfigurableEnvironment)
* {@inheritDoc}
* &p&If {@code null}, a new environment will be initialized via
* {@link #createEnvironment()}.
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = this.createEnvironment();
return this.
* Create and return a new {@link StandardServletEnvironment}. Subclasses may override
* in order to configure the environment or specialize the environment type returned.
protected ConfigurableEnvironment createEnvironment() {
return new StandardServletEnvironment();
从上述代码中我们可以看到默认情况下的
environment=new StandardServletEnvironment()
StandardServletEnvironment 后续章节讲到,这里我们仅仅看作Spring抽象了一个Environment来表示环境配置。
3. 继承了EnvironmentCapable
* Interface indicating a component that contains and exposes an {@link Environment} reference.
* &p&All Spring application contexts are EnvironmentCapable, and the interface is used primarily
* for performing {@code instanceof} checks in framework methods that accept BeanFactory
* instances that may or may not actually be ApplicationContext instances in order to interact
* with the environment if indeed it is available.
* &p&As mentioned, {@link org.springframework.context.ApplicationContext ApplicationContext}
* extends EnvironmentCapable, and thus exposes a {@link #getEnvironment()} however,
* {@link org.springframework.context.ConfigurableApplicationContext ConfigurableApplicationContext}
* redefines {@link org.springframework.context.ConfigurableApplicationContext#getEnvironment
* getEnvironment()} and narrows the signature to return a {@link ConfigurableEnvironment}.
* The effect is that an Environment object is 'read-only' until it is being accessed from
* a ConfigurableApplicationContext, at which point it too may be configured.
* @author Chris Beams
* @since 3.1
* @see Environment
* @see ConfigurableEnvironment
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment()
public interface EnvironmentCapable {
* Return the {@link Environment} associated with this component.
Environment getEnvironment();
4.&Environment&环境配置信息
EnvironmentCapable 接口和EnvironmentAware分别实现抽象了
Environment getEnvironment();
void setEnvironment(Environment environment);
它的主要几个实现如下所示:
MockEnvironment:模拟的环境,用于测试时使用;
StandardEnvironment:标准环境,普通Java应用时使用,会自动注册System.getProperties() 和 System.getenv()到环境;
public class StandardEnvironment extends AbstractEnvironment {
/** System environment property source name: {@value} */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value} */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())); //System.getProperties();
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));//System.getenv()
StandardServletEnvironment:标准Servlet环境,其继承了StandardEnvironment,Web应用时使用,除了StandardEnvironment外,会自动注册ServletConfig(DispatcherServlet)、ServletContext及JNDI实例到环境;
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
/** Servlet context init parameters property source name: {@value} */
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
/** Servlet config init parameters property source name: {@value} */
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
/** JNDI property source name: {@value} */
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
super.customizePropertySources(propertySources);
public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
& &&HttpServletBean分别实现了HttpServlet,EnvironmentCapable,EnvironmentAware.
& &简单扩展HttpServlet,给各种类型的servlet提供了一个便利的超类,提供了对属性的操作。
& 关于属性操作,会在下一步文件中介绍。
阅读(...) 评论()Spring MVC国际化配置 - 不再犹豫 - ITeye技术网站
博客分类:
一、基于浏览器语言的国际化配置
使用Spring的MVC,并且配置中有配置Resource文件
&!-- 资源文件绑定器 --&
&bean id="messageSource"class="org.springframework.context.support.ResourceBundleMessageSource"&
&property name="basename" value="message-info" /&
&property name="useCodeAsDefaultMessage" value="true" /&
其中,message-info是你的properties文件的通用名。如:我的配置文件叫message-info.properties,message-info_zh_CN.properties等等,只要有了这个配置,然后配置JSP渲染器为JSTL支持的,那么在你的JSP文件中使用fmt标记就可以实现客户浏览器语言国际化了。
如:&fmt:message key="info.login.title" /&
其中的info.login.title和你的资源文件对应.
另外一种方式是使用spring自带的标签显示国际化信息,如:
&spring:message code="main.title" /&&br&
&input type="button" value="&spring:message code="main.title" /&"/&&br&
二、基于动态加载的国际化配置
1、基于请求的国际化配置
基于请求的国际化配置是指,在当前请求内,国际化配置生效,否则自动以浏览器为主。
配置方式如下:
首先配置拦截器
&!-- 国际化操作 拦截器 必需配置,可以和其它国际化方式通用 --&&&&&&
&bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /&
这个配置呢,是不论请求级别的国际化,还是Cookie级别的国际化,再或者Session级别的国际化,都必需有配置这个拦截器,否则会不能使用。
配好上面的拦截器之后,就将拦截器注入到你的UrlHandlerMapping中,例如:
&bean id="defaultUrlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"&
&property name="interceptors" ref="localeChangeInterceptor" /&
&property name="order"&
&value&1&/value&
&/property&
这个时候,但凡有了符合UrlMapping的请求,就会被拦截,并且开始配置国际化参数
&&&&&&& &bean id="localeResolver" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver"&&&&&&&& &/bean&
默认的参数名为locale主意大小写。里面放的就是你的提交参数。如:en_US,zh_CN之类的,这个时候,你在页面上加一句&a href="?locale=zh_CN"&简体中文&/a&
如果你的资源中,饱含建议中文的配置,那么就会变成你确定的简体中文拉。
2、基于Session的国际化配置
拦截器和基于请求的相同
Session的配置如下:
&&&&&&& &bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver"&&/bean&&
在你的处理的Controller中,将提交上来的locale字段信息生成真正的Locale对象,然后将对象保存在Session中,默认保存的ID是SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME
这样,当你的Session不过期,那么语言种类始终保持正确的说。我一直是这样子用的,我觉得还是Session的好,老外们用了很满意。
3、基于Cookie的国际化配置
这个我就不说了,反正用的不多,至少我做的项目能不用Cookie就不用Cookie,所以,基于Cookie的国际化配置我就不细说了,如果想知道怎么配置,那么下载一个Spring,其中的例子程序就是用Cookie配置的,你自己读代码就OK了。
三、注意事项
如果不用默认的浏览器语言国际化方式,那么拦截器一定要配置,如果你有多个UrlMapping,那么就每个都配上拦截器。
至于配置的LocaleResolver的名字,一定要用上面的配置中的名字localeResolver当然了,这个是默认的名字来的,自己设置成别的也可以,但是就是麻烦,反正我用默认的就感觉不错
解决问题:
在前几天引用“Spring 的MVC I18N-国际化相关配置 ”并做了测试,发现 有一问题。程序运行会抛出异常
“Cannot change HTTP accept header - use a different locale resolution strategy”,根本原因是spring source 做了限制,源码如下
public class AcceptHeaderLocaleResolver implements LocaleResolver {
public Locale resolveLocale(HttpServletRequest request) {
return request.getLocale();
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
throw new UnsupportedOperationException(
"Cannot change HTTP accept header - use a different locale resolution strategy");
请注意上面的类,该类允许继承,所以需要改写setLocale方法,源码示范如下
package org.springframework.web.servlet.i18n;
import java.util.L
import javax.servlet.http.HttpServletR
import javax.servlet.http.HttpServletR
import org.springframework.web.servlet.DispatcherS
import org.springframework.web.servlet.LocaleR
public class MyAcceptHeaderLocaleResolver extends AcceptHeaderLocaleResolver {
private Locale myL
public Locale resolveLocale(HttpServletRequest request) {
return myL
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
然后在action-servlet.xml里的设置为
&bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"&
&property name="basename" value="message" /&
&bean id="myViewController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" /&
&bean id="filenameController" class="org.springframework.web.servlet.mvc.UrlFilenameViewController" /&
&bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&
&property name="interceptors" ref="localeChangeInterceptor"/&
&property name="mappings"&
chinese.do=filenameController
us.do=filenameController
&/property&
&bean id="defaultHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /&
&bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /&
&bean id="localeResolver" class="org.springframework.web.servlet.i18n.MyAcceptHeaderLocaleResolver"/&
&bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"&
&property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" /&
&property name="prefix" value="/WEB-INF/jsp/" /&
&property name="suffix" value=".jsp" /&
浏览 13099
浏览: 76806 次
来自: 北京
spring mvc demo教程源代码下载:http://w ...
请教一下楼主,spring-mvc国际化的官方资料在哪,能给个 ...
感觉楼主的配置文件好像写的不太正确
谢谢,正在从Myeclipse转到NetBeansMyecli ...SpringMVC,3种不同的URL路由配置方法(这根本不是一个小问题) - 推酷
SpringMVC,3种不同的URL路由配置方法(这根本不是一个小问题)
SpringMVC中配置URL拦截,非常简单。网上找个示例,就能通过。但是,在我做了好几个Web项目,又参与了别人主导的Web项目时,发现URL配置也非常有学问。
1. 先说说一种比较常见的:
&servlet-name&theDispatcher&/servlet-name&
&servlet-class&org.springframework.web.servlet.DispatcherServlet&/servlet-class&
&init-param&
&param-name&contextConfigLocation&/param-name&
&param-value&classpath:spring/spring-mvc-servlet.xml&/param-value&
&/init-param&
&load-on-startup&1&/load-on-startup&
&/servlet&
&servlet-mapping&
&servlet-name&theDispatcher&/servlet-name&
&url-pattern&*.html&/url-pattern&
&/servlet-mapping&
让SpringMVC指拦截 动态请求,js、css、img等静态资源不经过Spring,直接让Web容器处理。
如果配置了拦截器,也只会拦截.html动态请求。
静态资源不走Spring,也不走拦截器,性能当然是比较好的。
如果使用了Nginx,配置静态资源拦截,让Nginx处理静态资源的访问。因为Nginx在处理静态资源方面,比Tomcat等Web容器要强。
缺点:这种拦截动态请求的方法,比较死板。
2.& 我自己经常有一种需求,
这种不指定.html后缀的其实也是 动态请求,所以我在配置url-pattern喜欢用“/”,即拦截所有的请求。URL是可以灵活配置了,问题又来了,静态资源不再由Tomcat处理,所以必须在SpringMVC中再次配置,
&mvc:resources mapping=&/static/**& location=&/static/& /&
让SpringMVC把static静态资源也处理了。显然,让SpringMVC处理静态资源的性能没有Tomcat直接处理比较高。
理论上,请求中转的次数越多,&性能越差。
本以为万事大吉,虽然静态资源的性能较低,至少程序可以正常运行了,“反正是混过去了”。
进一步的需求,如果在Spring中配置了登录等拦截器,这个时候也会把 静态资源给拦截进来。
&mvc:resources mapping=&/static/**& location=&/static/& /& 这种URL映射,也无法逃脱拦截器的魔爪。
我是怎么发现这个问题的呢?
public class BaseLoginInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
LoginUtil.setCurrentUser(null);
initCurrentUser(request, response);
HandlerMethod handlerMethod = (HandlerMethod)
公司的项目,Boss的登录拦截器配置如上,“
HandlerMethod handlerMethod = (HandlerMethod)
”。但是我在自己的项目中,发现这行代码是有问题的。如果静态资源被拦截到,会报错:
java.lang.ClassCastException: org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to org.springframework.web.method.HandlerMethod
通过异常可以发现,&
Object handler是
ResourceHttpRequestHandler
HandlerMethod。
mvc:resources把静态资源请求交给了
ResourceHttpRequestHandler
处理,因此强制转换是有问题的。
公司项目中Boss的配置之所以没有出现问题,是因为他配置的是只拦截“.html”&动态请求,所以强制转换总是成立的。
---------------------------------------------
我们分析了上述两种情况, 发现“根本矛盾”“根本需求”是啥?
1.动态请求的URL应该非常灵活,/news /news.html都应该算作动态请求。
2.SpringMVC的url-pattern可以配置 / , *.html,或者正则表达式,但是我不太喜欢用正则表达式。
3.如果可能,SpringMVC最好不要拦截静态资源,让Tomcat容器直接处理更好。
&mvc:resources mapping=&/static/**& location=&/static/& /&
这是为了性能考虑。
4.如果线上服务器配置了Nginx,我可以选择让Nginx拦截静态请求,因为比Tomcat处理性能更高。
本地是否配置Nginx,都不需要改动任何代码。
-------------------------------------------------
上面说的 第一种方法的缺陷是,url配置不够灵活。
第二种方法的缺陷是,SpringMVC要拦截静态资源,而且登录拦截器 也会拦截 静态资源,不但性能差,程序还得再次修改,判断HandlerMethod的实际类型。
3.终极解决方案:&
以我习惯用的第2种方法为基础,进一步改进:
&mvc:resources mapping=&/static/**& location=&/static/& /&,不做静态资源请求的映射。
在web.xml里增加如下配置:
&servlet-mapping&
&servlet-name&default&/servlet-name&
&url-pattern&/static/*&/url-pattern&
&/servlet-mapping&
&servlet-mapping&
&servlet-name&default&/servlet-name&
&url-pattern&*.js&/url-pattern&
&/servlet-mapping&
&servlet-mapping&
&servlet-name&default&/servlet-name&
&url-pattern&*.css&/url-pattern&
&/servlet-mapping&
激活Tomcat的defaultServlet来处理静态文件。
网友提问:
这样 SpringMVC不再响应静态资源,登录拦截器也没有问题了。
------------------------------------------------------------------------
详细讨论了上诉3种情况,我的结论是:URL配置根本不是一个简单的问题。
搞IT这门高科技技术的Coder,真心需要研究啊。今天搞点小功能,遇到各种问题,探究了好久,才理清了脉络,单单是解决问题,而不能找到根本原因,在遇到下一个问题的时候,会再次束手无策。
原文首发:
已发表评论数()
&&登&&&录&&
已收藏到推刊!
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见

我要回帖

更多关于 spring mvc 的文章

 

随机推荐