而在其它的編輯器中,默認保存的內(nèi)容都是GB2312或者GBK(NOTEPAD中對應ANSI).而根據(jù)前面所說的UTF-8和GBK,GB2312等的編碼值是不同的這一點,可以知道,如果文件使用了UTF-8,那么字符編碼就必須使用UTF-8,否則編碼值的不同就可能造成亂碼。而這也就是為什么那么多的人使用了UTF-8編碼后還會產(chǎn)生亂碼的根本原因。(JS和JSP都是這個道理)
3、JSP,STRUTS等的中文亂碼解決方案
?????其實解決的方法只有一個:
???方法只有一種,但處理方式就多種多樣了,初學者會在JSP頁面上直接使用,而有經(jīng)驗的程序員會使用過濾器。而現(xiàn)在所要說的方法也是過濾器。這里以統(tǒng)一使用UTF-8作為編碼作為例子說明。具體過程就不多說了,網(wǎng)上有很多教程。偷懶一點的,到TOMCAT中復制就行了。在TOMCAT的目錄下的\webapps\jsp-examples\WEB-INF\classes\filters\找到SetCharacterEncodingFilter.java 這個類,放到你的程序中并配置好映射路徑。配置好后基本上你的亂碼問題就解決了。但要映射路徑中需要注意的就是不能使用 '*'
像上面這樣配置的話(可能也是網(wǎng)上大多教程的做法,想當年也是害苦了我),可能你只有JSP的亂碼解決了,要解決STRUTS的亂碼需要映射 *.do 或者 servletActionName。然后在初始化參數(shù)中設置encoding的值就行了。
當然,最重要的是要記得根據(jù)前面所說的方法,改變你所使用的編輯器保存文件的編碼要與使用的字符編碼一致。
而在JSP內(nèi)容中,還是使用如網(wǎng)上教程所說的那種技倆,在所有頁面的頁首加入:
?contextLoader的源碼
?public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
?? throws BeansException {
? long startTime = System.currentTimeMillis();
? if (logger.isInfoEnabled()) {
?? logger.info("Root WebApplicationContext: initialization started");
? }
? servletContext.log("Loading Spring root WebApplicationContext");
? try {
?? // Determine parent for root web application context, if any.
?? ApplicationContext parent = loadParentContext(servletContext);
?? WebApplicationContext wac = createWebApplicationContext(servletContext, parent);
?? servletContext.setAttribute(
???? WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, wac);
?? if (logger.isInfoEnabled()) {
??? logger.info("Using context class [" + wac.getClass().getName() +
????? "] for root WebApplicationContext");
?? }
?? if (logger.isDebugEnabled()) {
??? logger.debug("Published root WebApplicationContext [" + wac +
????? "] as ServletContext attribute with name [" +
????? WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
?? }
?? if (logger.isInfoEnabled()) {
??? long elapsedTime = System.currentTimeMillis() - startTime;
??? logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
?? }
?? return wac;
? }
? catch (RuntimeException ex) {
?? logger.error("Context initialization failed", ex);
?? servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
?? throw ex;
? }
? catch (Error err) {
?? logger.error("Context initialization failed", err);
?? servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
?? throw err;
? }
?}
?注意WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,這里面放了WebApplicationContext,需要使用時從ServletContext取出
?可以使用WebApplicationContextUtils得到WebApplicationContext
?public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
? Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
? if (attr == null) {
?? return null;
? }
? if (attr instanceof RuntimeException) {
?? throw (RuntimeException) attr;
? }
? if (attr instanceof Error) {
?? throw (Error) attr;
? }
? if (!(attr instanceof WebApplicationContext)) {
?? throw new IllegalStateException("Root context attribute is not of type WebApplicationContext: " + attr);
? }
? return (WebApplicationContext) attr;
?}
?關鍵的問題在于struts如何啟動的spring的,ContextLoaderPlugIn的源碼
?
?// Publish the context as a servlet context attribute.
? String attrName = getServletContextAttributeName();
? getServletContext().setAttribute(attrName, wac);
?
?public String getServletContextAttributeName() {
? return SERVLET_CONTEXT_PREFIX + getModulePrefix();
?}
?不同加載的Key竟然不同,原因就是WebApplicationContext放在那里的問題,可spring調(diào)用的時候會根據(jù)WebApplicationContext里面定義的那個名字去找的,問題出在這里
?在struts-config.xml中配置
??? <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
????? <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" />
??? </plug-in>
??? <controller>
??????? <set-property property="processorClass" value="org.springframework.web.struts.DelegatingRequestProcessor" />
??? </controller>
?原理是這樣的,Struts雖然只能有一個ActionServlet實例,但是對于不同的子應用分別能有自己的RequestProcessor實例每個RequestProcessor實例分別對應不同的struts配置文件。
?? 子應用的ProcessorClass類必須重寫一般就是繼承RequestProcessor類,然后再其配置文件的controller元素中的<processorClass>屬性中作出修改。那么當
? getRequestProcessor(getModuleConfig(request)).process(request,response);就能根據(jù)request選擇相應的moduleconfig,再根據(jù)其<processorClass>屬性選擇相應的RequestProcessor子類來處理相應的請求了。
?
ServletContext 被 Servlet 程序用來與 Web 容器通信。例如寫日志,轉(zhuǎn)發(fā)請求。每一個 Web 應用程序含有一個Context,被Web應用內(nèi)的各個程序共享。因為Context可以用來保存資源并且共享,所以我所知道的 ServletContext 的最大應用是Web緩存----把不經(jīng)常更改的內(nèi)容讀入內(nèi)存,所以服務器響應請求的時候就不需要進行慢速的磁盤I/O了。
ServletContext 被 Servlet 程序用來與 Web 容器通信。例如寫日志,轉(zhuǎn)發(fā)請求。每一個 Web 應用程序含有一個Context,被Web應用內(nèi)的各個程序共享。因為Context可以用來保存資源并且共享,所以我所知道的 ServletContext 的最大應用是Web緩存----把不經(jīng)常更改的內(nèi)容讀入內(nèi)存,所以服務器響應請求的時候就不需要進行慢速的磁盤I/O了。
ServletContextListener 是 ServletContext 的監(jiān)聽者,如果 ServletContext 發(fā)生變化,如服務器啟動時 ServletContext 被創(chuàng)建,服務器關閉時 ServletContext 將要被銷毀。
在JSP文件中,application 是 ServletContext 的實例,由JSP容器默認創(chuàng)建。Servlet 中調(diào)用 getServletContext()方法得到 ServletContext 的實例。
我們使用緩存的思路大概是:
服務器啟動時,ServletContextListener 的 contextInitialized()方法被調(diào)用,所以在里面創(chuàng)建好緩存??梢詮奈募谢蛘邚臄?shù)據(jù)庫中讀取取緩存內(nèi)容生成類,用 ervletContext.setAttribute()方法將緩存類保存在 ServletContext 的實例中。
程序使用 ServletContext.getAttribute()讀取緩存。如果是 JSP,使用a pplication.getAttribute()。如果是 Servlet,使用 getServletContext().getAttribute()。如果緩存發(fā)生變化(如訪問計數(shù)),你可以同時更改緩存和文件/數(shù)據(jù)庫。或者你等 變化積累到一定程序再保存,也可以在下一步保存。
服務器將要關閉時,ServletContextListener 的 contextDestroyed()方法被調(diào)用,所以在里面保存緩存的更改。將更改后的緩存保存回文件或者數(shù)據(jù)庫,更新原來的內(nèi)容。
import User; //my own class
import DatabaseManager; // my own class
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
public class MyContextListener
implements ServletContextListener {
private ServletContext context = null;
public void contextInitialized(ServletContextEvent event) {
context = event.getServletContext();
User user = DatabaseManager.getUserById(1);
context.setAttribute("user1", user);
}
public void contextDestroyed(ServletContextEvent event) {
User user = (User)context.getAttribute("user1");
DatabaseManager.updateUserData(user);
this.context = null;
}
}
你實現(xiàn)(implements)了 ServletContextListener 編譯后,把它放在正確的WEB-INF/classes目錄下,更改WEB-INF目錄下的 web.xml文件,在web-app節(jié)點里添加
<listener>?來自:
<listener-class>MyServletContextListener</listener-class>
</listener>