1. 程式人生 > >一個簡單的Java Web專案搭建流程

一個簡單的Java Web專案搭建流程

今天試圖在伺服器上搭建一個web伺服器,順便回顧了java web專案的入門,使用Servlet處理HTTP請求,並記錄日誌等操作。當很久沒有做過web專案時,有些東西還是很容易忘記的。

Maven配置

使用maven進行整個專案的構建,使用intellij idea IDE,填寫完groupIdartifactId之後,宣告packaging元素為war包,在build中注意需要設定war-pluginwebResources

<plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1.1</version>
                <configuration>
                    <webResources>
                        <resource>
                            <directory>web</directory>
                        </resource>
                    </webResources>
                </configuration>
            </plugin>
        </plugins>
 

其中的dependency項中除了要包含的依賴jar包外,有些編譯期依賴的jar包也需要填寫(scope=provided),比如javaee-api

Servlet編寫和配置

Java Web專案中使用Servlet來處理具體的http請求,請求url的處理是配置在webResources目錄下的web.xml檔案中的:

<servlet>
        <servlet-name>monitor</servlet-name>
        <servlet-class>具體的ServletClass</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>monitor</servlet-name>
        <url-pattern>/monitor</url-pattern>
</servlet-mapping>

其中servlet-mapping中的/monitor就是對應的處理URL,也即web伺服器埠/web專案的Context/url-pattern

Servlet中通常繼承javax.servlet.http.HttpServlet類,重寫其中的doGetdoPost方法(分別處理GETPOST請求)。事實上,Servlet中包含HTTP的所有請求方式的相關方法(PUT, DELETE等)一般情況下,我們對於資料量稍微比較大的資料都使用POST方式提交HTTP請求(GET方式一般用於查詢資源,會限制提交資料長度,GET請求的引數資料會顯示在瀏覽器的位址列URL中)。

通過HttpServletRequest.getParameter(parameterName)

來獲取請求中提交的引數資料,這裡指的僅僅是Request範圍的引數名。

Servlet的資料返回

如何返回Servlet中的資料,這需要我們使用引數中的HttpServletResponse的相關方法了,其中getWriter()方法提供了一個輸出流,可以將html中的資料寫入到這個輸出流中,這樣在瀏覽器就能以頁面到形式檢視到這個html頁面。

Servlet可以以Java程式的方式對請求進行處理並返回,可以說,ServletJava程式碼中包含html頁面,如果生成的html頁面比較大,其中的getWriter().print()的程式碼會非常恐怖而且難以理解。JSP正是基於這個原因出現的,JSP使用的方式是html頁面加入java程式碼(scriptlet),在html頁面較大而java邏輯較少的情況下比較適用。

Servlet中也可以根據處理邏輯來forword到對應的jsp頁面,使用如下的方法:

   getServletConfig().getServletContext().getRequestDispatcher(jsp的相對路徑).forward(request,response);

我們知道HTTP返回的程式碼代表這不同的含義,比如

1xx-資訊提示;
2xx-成功;
3xx-重定向;
4xx-客戶端錯誤;
5xx-伺服器錯誤;

我們可以手動在HttpServletResponse.setStatus()方法中指定返回的HTTP Code,給客戶端對應的提示。

Web專案處理邏輯中,經常需要處理本地資源,比如讀取本地(Web專案中)的配置檔案。這就需要使用ServletContext中的getResource系列方法, getResourcegetResourceAsStream方法以“/”開頭的字串為引數,它指定上下文根路徑的資源相對路徑。文件的層級可能存在於伺服器的檔案系統,war檔案,遠端伺服器或者在一些其它位置中,注意在使用完成後,需要將流關閉。

日誌(log4j)配置

在進行任何專案開發都需要記錄必要的日誌,尤其是對應web專案的開發,你需要能夠查詢到對應的處理錯誤,這裡使用了log4j來進行日誌的處理。

日誌的配置需要進行初始化,這個初始化的時機需要在web專案啟動時做。這裡就需要為log4j單獨建立一個Servlet,用於初始化。在web.xml中建立對應的Servlet,並不需要宣告servlet-mapping,因為它並不負責真正處理HTTP請求。

<servlet>
        <servlet-name>log4j-init</servlet-name>
                  <servlet-class>com.xxx.monitor.servlet.Log4jInitServlet</servlet-class>
        <init-param>
            <param-name>log4j</param-name>
            <param-value>WEB-INF/log4j.properties</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
</servlet>

將其load-on-startup宣告的順序改成1,這樣就能保證在其他Servlet初始化之前,Log4j已經初始化完畢。其中的init-param引數指定了log4j配置檔案對應WebResources的位置,這在ServletConfig中可以通過getInitParameter來進行獲取。

Log4jInitServlet中,由於不需要處理HTTP的各種型別請求,只需要重寫初始化方法init

@Override
    public void init(ServletConfig servletConfig) throws ServletException {
        String prefix = servletConfig.getServletContext().getRealPath("/");
        String filePath = String.format("%s/%s", prefix, servletConfig.getInitParameter("log4j"));
        FileInputStream inputStream = null;
        Properties properties = new Properties();
        try {
            inputStream = new FileInputStream(new File(filePath));
            properties.load(inputStream);
            String logFilePath = String.format("%s%s", prefix, properties.getProperty("log4j.appender.R.File"));
            properties.setProperty("log4j.appender.R.File", logFilePath);
 
            PropertyConfigurator.configure(properties);
        } catch (IOException e) {
            throw new ServletException("log4j module initialized failed!");
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                }
            }
        }
}

這裡log4j.properties中的log4j.appender.R.File引數只是指定輸出log檔案的相對地址,這就需要我們使用servletConfig.getServletContext().getRealPath("/")將其拼接成執行時的絕對地址。

HTTP請求測試

在編寫程式碼完後,我們都需要對其正確性進行測試。Java中提供了對於HTTP請求傳送的相關API,在這個基礎上,我們進行測試程式碼的編寫:

URL postUrl = null;
        try {
            postUrl = new URL(url);
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        }
        HttpURLConnection connection = null;
        DataOutputStream dataOutputStream = null;
        BufferedReader reader = null;
        try {
            connection = (HttpURLConnection) postUrl.openConnection();
            //Read from the connection
            connection.setDoInput(true);
            //http body is in the content
            connection.setDoOutput(true);
            //we use post method
            connection.setRequestMethod("POST");
            //post can't use caches
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
 
            connection.connect();
            dataOutputStream = new DataOutputStream(connection.getOutputStream());
            String content = "userName=clamaa&password=bbb&json=jsonstring";
            dataOutputStream.writeBytes(content);
            dataOutputStream.flush();
            dataOutputStream.close();
 
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
 
            System.out.println("====================");
            System.out.println("read line started...");
            StringBuilder result = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
                result.append(line).append(System.getProperty("line.separator"));
            }
            System.out.println("====================");
            return result.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                }
            }
        }

至此,一個基本的Java專案就已經編寫完畢,由於整個專案使用maven來構建的,只要在專案目錄下,執行maven clean install命令,將生成的target/下的war包部署到tomcatwebapp目錄下即可。