Java Web系列:Java Web 項目基礎


1.Java Web 模塊結構

JSP文件和AXPX文件類似,路徑和URL一一對應,都會被動態編譯為單獨class。Java Web和ASP.NET的核心是分別是ServletIHttpHandler接口,因此無論是基礎的Page文件(JSP、ASPX)方式還是后來發展的MVC方式(Spring MVC、ASP.NET MVC)都是基於核心接口的基礎上再次封裝和擴展(DispatcherServletMvcHandler)。

除JSP文件外,其他全部文件部署在應用目錄的WEB-INF子目錄下,WEB-INF目錄可以認為是ASP.NET中將web.config文件、bin目錄和App_開頭的運行時目錄存放在了一個統一的根目錄中。

Java Web的配置文件web.xml也存放在WEB-INF目錄下,而ASP.NET的配置文件web.config一般直接存放在應用目錄下(ASP.NET其他目錄同樣可以有web.config文件)。ASP.NET將所有的引用和代碼生成的dll都部署在bin中,而Java Web的引用jar和生成的class分別存放在WEB-INF的子目錄lib和classes中(參考1)。

綜上,類似ASP.NET中的web.config、bin、App_Data等,Java Web中的WEB-INF、web.xml、lib和classes是我們必須了解和掌握的。

|--Assembly Root
  |---WEB-INF/
    |--web.xml
    |--lib/
    |--classes/
  1. WEB-INF目錄:Java Web文件的根目錄。
  2. web.xml文件:配置文件(asp.net web.config)。
  3. lib目錄:存放類庫文件(asp.net bin)。
  4. classes目錄:存放class文件(asp.net bin)。

2.Java Web項目的基本結構[Eclipse Dynamic Web Project]

Eclipse Dynamic Web Project項目

(1)可以配置需要編譯的源碼目錄和輸出目錄,默認編譯src目錄下的源文件到build\classes目錄下。

(2)可以配置WEB-INF的根目錄,默認為WebContent

(3)可以選擇是否生成默認web.xml文件。

我們創建一個命名為DynamicWP的默認生成web.xml的Dynamic Web Proejct項目。文件結構如下:

|--DynamicWP
  |--.settings/
  |--build/
    |--classes/
  |--src/
  |--WebContent/
    |--META-INF/
      |--MANIFEST.MF
    |--WEB-INF/
      |--web.xml
      |--lib/

在Eclipse的項目資源管理器中DyanmicWP項目的視圖如下:

|--DynamicWP
  |--Deployment Desciptor
  |--JAX-WS Web Services
  |--Java Resources
  |--JavaScript Resources
  |--build
  |--WebContent
    |--META-INF/
      |--MANIFEST.MF
    |--WEB-INF/
      |--web.xml
      |--lib/
  1. .settings為Eclipse項目文件夾,存放了Eslipse項目的各種配置。在Eclipse項目視圖中不可見。
  2. src目錄存放源碼。在Eclipse的項目視圖中對應為Java Resources/src。
  3. build存放編譯后的文件。
  4. 可以在類似的\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\DynamicWP目錄中查看運行時的文件結構。

3.Maven Web項目的基本結構

鑒於目前Java IDE眾多並且都有一定的擁泵,Eclipse的Java Web項目不具有可移植性。Maven即解決了項目結構的規范問題又提供了強大引用處理等強大的功能,在項目布局等方面已經是目前事實上的標准。Maven項目的主要結構如下(參考2):

|--root
  |--pom.xml
  |--src/
    |--main/
      |--java/
      |--resources/
      |--webapp/
    |--test/
      |--java/
      |--resources
  |--target/

Eclipse中新建一個Maven web app項目。文件結構如下:

|--MavenWP
  |--pom.xml
  |--.project
  |--.classpath
  |--.settings/
  |--src/
  |--target/
    |--classes/
    |--m2e-wtp/
  1. pom.xml:maven項目配置文件。
  2. .project文件和.classpath文件以及.settings目錄和target/m2e-wtp目錄下的文件為Eclipse項目配置文件。
  3. src和target:maven標准項目目錄。

Eclipse4.5.1中對應的項目資源管理視圖

|--MavenWP
  |--Deployment Desciptor/
  |--Java Resources/
  |--JavaScript Resources/
  |--Deployed Resources/
  |--src
  |--target
  |--pom.xml
  1. 默認創建的項目會添加一個index.jsp並報錯:使用maven搜索並添加servlet依賴更新后就可以正常運行。
  2. Java構建路徑問題警告:使用maven搜索並添加compiler插件並配置configuration節點更新就可以消除。
  3. 牆的問題配置maven鏡像,我采用的是http://maven.oschina.net/content/groups/public/。
  4. 默認創建的maven webapp缺少的src/main/java、src/test/java和src/test/resources等目錄需要自己手動添加。
  5. 修改.settings/org.eclipse.wst.common.project.facet.core.xml,更新<installed facet="jst.web" version="3.1"/>。
  6. web.xml根節點開始部分修改如下:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">

 

Maven的配置文件pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>me.test</groupId>
    <artifactId>MavenWP</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>MavenWP Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>MavenWP</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.3</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

4.servlet基礎

正如ASP.NET的核心是IHttpHandler一樣,Java Web的核心是Servlet接口,位於javax.servlet命名空間中。Filter的概念可以參考ASP.NET的HttpModule,Servlet中的各種Listener可以參考ASP.NET HttpApplicaiton中類似的event。無論是Java還是.NET的Web技術,都是基於HTTP協議的具體實現。Java Web和ASP.NET中的一些核心項對應如下:

  Java 參考3 .NET 備注
Core javax.servlet.Servlet System.Web.IHttpHandler  
HTTP Request javax.servlet.ServletRequest System.Web.HttpRequest  
HTTP Response javax.servlet.ServletResponse System.web.HttpResponse  
Cookie javax.servlet.http.Cookie System.Web.HttpCookie  
Session javax.servlet.http.HttpSession System.Web.HttpSessionState  
Application javax.servlet.ServletContext System.Web.HttpApplication  
Begin Request javax.servlet.Servlet.RequestDispatcher System.Web.HttpApplication.BeginRequest event 
Begin\End Request javax.servlet.Servlet.ServletRequestListener System.Web.HttpApplication.BeginRequest\EndRequest event 
Filter javax.servlet.Filter System.Web.IHttpModule  
Application Event javax.servlet.ServletContextListener System.Web.HttpApplication.Application_Start\Application_End method

Servlet和ASP.NET的簡化示意圖:

用於簡化web.xml配置的Servlet的注解(3.0開始支持,在ASP.NET中沒有對應項):

(1)WebServlet:作用在javax.servlet.http.HttpServlet的實現類上。

(2)WebFilter:作用在javax.servlet.Filter的實現類上。

(3)WebListener:作用在Listener的實現類上(javax.servlet.ServletContextListener、javax.servlet.ServletContextAttributeListener、javax.servlet.ServletRequestListener、javax.servlet.ServletRequestAttributeListener、javax.servlet.http.HttpSessionListener、javax.servlet.http.HttpSessionAttributeListener)。

(4)WebInitParam:結合WebServlet和WebFilter注解用來配置屬性。

(5)MultipartConfig:作用在javax.servlet.http.HttpServlet的實現類上。標注請求是mime/multipart類型。

用於Servlet容器初始化的ServletContainerInitializer(可實現無web.xml,3.0開始支持,可類比ASP.NET的Application_Start方法):

(1)Servlet容器啟動時查找ServletContainerInitializer的實例。

(2)ServletContainerInitializer實例使用HandlesTypes標注一個或多個類型,Servlet容器將在啟動時掃描classpath,獲取這些類型的實例。

(3)Servlet容器在啟動時調用ServletContainerInitializer實現類的onStartup方法,該方法可以獲取HandlesTypes標注的所有類型對象。

5.自定義Session

Session在存儲安全性要求較高的會話信息方面是必不可少的,Session當然絕對不是用來存儲用戶登錄狀態的,但類似驗證碼等敏感信息卻必須存儲在Session中。對於分布式Web應用自定義Session支持獨立的狀態服務器或集群是必須的。

ASP.NET通過SessionStateModule通過配置文件配置實際的Session提供程序,Session提供程序實現了SessionStateStoreProviderBase,因此在ASP.NET中實現自定義Session是通過繼承SessionStateStoreProviderBase實現,配置Session是通過Web.config。ASP.NET自定義session的代碼參考github上的開源項目SQLiteSessionStateStore

同理,Java Servlet中使用自定義Session通過Filter可以實現。由於不同的servlet容器對Session的實現不同,所以通用性最好的方式是繼承HttpServletRequestWrapper重寫getSession方法返回自定義的Session對象。Filter采用了職責鏈模式(chain of responsibility),HttpServletRequestWrapper采用了裝飾模式(Decorator),可以通過《Head First 設計模式》閱讀模式的相關內容。

(1)首先自定義繼承HttpSession的MySession(為了便於演示,僅包裝了容器的session並轉發調用)。

import java.util.Enumeration;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;

public class MySession implements HttpSession {

    private HttpSession _containerSession;

    public MySession(HttpSession session) {
        this._containerSession = session;
    }

    @Override
    public long getCreationTime() {
        return this._containerSession.getCreationTime();
    }

    @Override
    public String getId() {
        return this._containerSession.getId();
    }

    @Override
    public long getLastAccessedTime() {
        return this._containerSession.getLastAccessedTime();
    }

    @Override
    public ServletContext getServletContext() {
        return this._containerSession.getServletContext();
    }

    @Override
    public void setMaxInactiveInterval(int interval) {
        this._containerSession.setMaxInactiveInterval(interval);
    }

    @Override
    public int getMaxInactiveInterval() {
        return this._containerSession.getMaxInactiveInterval();
    }

    @SuppressWarnings("deprecation")
    @Override
    public HttpSessionContext getSessionContext() {
        return this._containerSession.getSessionContext();
    }

    @Override
    public Object getAttribute(String name) {
        return this._containerSession.getAttribute(name);
    }

    @SuppressWarnings("deprecation")
    @Override
    public Object getValue(String name) {
        return this._containerSession.getValue(name);
    }

    @Override
    public Enumeration<String> getAttributeNames() {
        return this._containerSession.getAttributeNames();
    }

    @SuppressWarnings("deprecation")
    @Override
    public String[] getValueNames() {
        return this._containerSession.getValueNames();
    }

    @Override
    public void setAttribute(String name, Object value) {
        this._containerSession.setAttribute(name, value);
    }

    @SuppressWarnings("deprecation")
    @Override
    public void putValue(String name, Object value) {
        this._containerSession.putValue(name, value);
    }

    @Override
    public void removeAttribute(String name) {
        this._containerSession.removeAttribute(name);
    }

    @SuppressWarnings("deprecation")
    @Override
    public void removeValue(String name) {
        this._containerSession.removeValue(name);
    }

    @Override
    public void invalidate() {
        this._containerSession.invalidate();
    }

    @Override
    public boolean isNew() {
        return this._containerSession.isNew();
    }

}
View Code

(2)自定義繼承HttpServletRequestWrapper的MyRequest

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;

public class MyRequest extends HttpServletRequestWrapper {

    public MyRequest() {
        super(null);
    }

    public MyRequest(HttpServletRequest request) {
        super(request);
        // TODO 自動生成的構造函數存根
    }

    @Override
    public HttpSession getSession(boolean create) {
        return new MySession(super.getSession(create));
    }

    @Override
    public HttpSession getSession() {
        return new MySession(super.getSession());
    }
}
View Code

(3)自定義Filter將Request包裝為MyRequest

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

@WebFilter("/*")
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO 自動生成的方法存根

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        chain.doFilter(new MyRequest((HttpServletRequest) request), response);

    }

    @Override
    public void destroy() {
        // TODO 自動生成的方法存根

    }

}
View Code

通過注解配置了Filter,也可以通過原始的web.xml方式配置。

6.參考

1.https://docs.oracle.com/javaee/7/tutorial/packaging003.htm

2.http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html

3.https://docs.oracle.com/javaee/7/tutorial/webapp005.htm

小結:

你至少應該知道的:

(1)配置文件:ASP.NET的web.config和Java的web.xml

(2)Web核心:ASP.NET的IHttpHandler接口和Java的Servlet接口

(3)攔截器:ASP.NET的HttpModule和Java的Filter

(4)應用程序事件:ASP.NET的HttpApplication event和Java的各種Listener

(5)啟動器:ASP.NET的Application_Start和Java的ServletContainerInitializer

(6)引用管理:ASP.NET的Nuget和Java的Maven

感想:

ASP.NET的核心對象不像Java Servlet一樣,從一開始就基於接口,這是缺點。但Java Servlet的核心對象全靠容器實現,就連HttpSession同樣如此,這也是缺點。比如自定義個Session十分麻煩,沒有像ASP.NET一樣簡單配置即可。另外Servlet的一些抽象定義有點過頭了,不夠簡潔。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM