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)。html

除JSP文件外,其餘所有文件部署在應用目錄的WEB-INF子目錄下,WEB-INF目錄能夠認爲是ASP.NET中將web.config文件、bin目錄和App_開頭的運行時目錄存放在了一個統一的根目錄中。java

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)。git

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

|--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項目web

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

(2)能夠配置WEB-INF的根目錄,默認爲WebContent設計模式

(3)能夠選擇是否生成默認web.xml文件。api

咱們建立一個命名爲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的一些抽象定義有點過頭了,不夠簡潔。

相關文章
相關標籤/搜索