如何制作JSP+Angular 的開發環境

我本身是一個Java Web Application developer, 最近在學Angular Framework,
發覺要分開來開發會出現很多問題(如 Angular routing, CORS),為了解決問題,
所以在Google  裡尋找解決方案,尋找到的解決方案如下:

  1. 改動Tomcat Server setting, 詳細可以 click這裡

  2. 用Servlet Filter 來做 URL redirect。

我不想改動Tomcat Server setting, 於是我用了第2個方案。
雖然有人已經做了一個UrlRewriteFilter可是做不到想要的効果,
最後經過一輪的Research 和測試之後終於做到了。

在解說之前, 我介紹一下我的資料夾結構:

E:.
└─workspace
    └─DemoWeb
        ├─frontEnd	<==這個資料夾是用來儲存Angular project 的檔案	
        └─jsp		<==這個資料夾是用來儲存Dynamic Web project 的檔案

再來,以下是我的開發環境:

  1. Eclipse Version 2019-06 (4.12.0)

  2. Angular CLI version 8.3.3

  3. Node version 10.16.3

  4. Tomcat version 8.5

  5. Windows 10

為方便解說, 我們先來做一個簡單Java Web Application:

  1. 打開Eclipse

  2. Click File -> New Project -> Dynamic Web Project

  3.  Click “Next", Project name 輸入"DemoWeb"

  4. Click “Finish"

  5. 右鍵點選這個 project , 點選"Java EE Tools" 來產生web.xml

  6. 最後在context root 加一個index.jsp 來展示這是JSP的"地盤"

  7. 在index.jsp裡面輸入以下內容:
    <%@ page language="java" contentType="text/html; charset=UTF-8″ pageEncoding="UTF-8″%>

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8″>
    <title>This is a JSP page.</title>
    </head>
    <body>
    <%="This is a JSP page." %>
    </body>
    </html>

  8. 然後按"Ctrl-S"儲存。

  9. 右鍵點選這個jsp, 點選"Run as" ,再點選"Run on Server", 此時Windows 的預設瀏覽器應會自動跑出來並顯示以下畫面:

  10. 此時回到Eclipse, 按下被紅圈圈著那個制去停止tomcat server:

再來建立Angular project:

  1. 打開VS code, 然後click File->Open Folder ,然後點選"E:\workspace\DemoWeb"

  2. 按"Ctrl-`", terminal 就會出現

  3. 然後在terminal 中下達以下命令來建立新的Angular project:

    ng new frontEnd

  4. 之後按"Y" 和按一下enter, 然後等待Angular project建立完成

  5. 點選左手邊的"frontEnd" ,再點選"src",再點選"app"

  6. 最後點選"app.component.html"這個檔案,

  7. 將這個檔案的內容全部刪去,換上以下內容:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8″>
    <title>This is Angular page.</title>
    </head>
    <body>
    This is Angular page.<br>
    <a href="admin/">Go To Admin. Page</a>
    <router-outlet></router-outlet>
    </body>
    </html>

  8. 再click terminal 一下,輸入以下指令進入我們剛剛新建Angular project目錄裡:

    cd frontEnd

  9. 接著再輸入:

    ng serve -o

  10. 此時Windows 的預設瀏覽器應會自動跑出來並顯示以下畫面:

  11. 此時再click terminal 一下回到terminal ,按"Ctrl-C" 來停止ng serve

制作Admin. Page

  1. 要制作Admin. Page 我們需要Admin. Page Component,
    輸入以下指令來產生Admin. Page Component

    ng g component Admin

制作Routing

  1. 點選"frontEnd"->src->app->app-routing.module.ts
  2. 加入routing


    import { NgModule } from ‘@angular/core’;

    import { Routes, RouterModule } from ‘@angular/router’;
    import { AdminComponent } from ‘./admin/admin.component’;
    const routes: Routes = [
    { path:  ‘admin’, component:  AdminComponent}
    ];

    @NgModule({
     imports: [RouterModule.forRoot(routes)],
     exports: [RouterModule]
    })

    export class AppRoutingModule { }

  3. 然後按"Ctrl-S"儲存。

測試Routing

  1. click terminal 一下,輸入以下命令:

    ng serve -o

  2. 此時Windows 的預設瀏覽器應會自動跑出來並顯示以下畫面:

  3. 瀏覽以下http://localhost:4200/admin,並顯示以下畫面:

  4. 此時再click terminal 一下回到terminal ,按"Ctrl-C" 來停止ng serve

設定Angular 的output folder

  1. 點選"frontEnd"->angular.json

  2. 將以下setting:

    “outputPath": “dist/frontEnd"

    改成

    “outputPath": “E:\\workspace\\DemoWeb\\jsp\\WebContent\\frontEnd",

  3. 然後按"Ctrl-S"儲存,之後Angular 會自動將已compile的js 檔案抄到eclipse 的project 目錄裡的frontEnd資料內。

  4. click terminal 一下輸入以下命令再啟動 ng serve:

    ng build –watch –base-href /DemoWeb/frontEnd/

    •  由於想tomcat server 執行angular code, 所以要用base href 來配合JSP application 的context path.

    • 由於output path setting 最尾是frontEnd, 所以這裡都尾都是frontEnd

根據這裡說,如果要Angular routing working properly, 就要將所有access /frontEnd 這個 folder 的request forward 到/frontEnd/index.html.要做到這樣的forward就要加入custom servlet filter,加入custom servlet filter步驟如下:

  1. 回到Eclipse,右鍵點選這個 project , 點選"New" ->"Filter"
  2. 輸入filter class name 和package name
  3. 點選 “Next",然後再點選 “/AngularFilter"
  4. 再點選 “Edit", 輸入"/frontEnd/*",再click “OK"
  5. 最後click “Finish"
  6. 此時會彈出編輯AngularFilter.java畫面
  7. 請用以下code 才取代原本的code:
    /*
     * Copyright 2004-2005 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.filter;
    import java.io.File;
    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.FilterRegistration;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    /**
     * @author Roy Tsang
     *
     */
    /**
     * Servlet Filter implementation class AngularFilter
     */
    @WebFilter("/frontEnd/*")
    public class AngularFilter implements Filter {
    	FilterConfig filterConfig;
        /**
         * Default constructor. 
         */
        public AngularFilter() {
            // TODO Auto-generated constructor stub
        }
    
    	/**
    	 * @see Filter#destroy()
    	 */
    	public void destroy() {
    		this.filterConfig = null;
    	}
    
    	/**
    	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
    	 */
    	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    		String destination,angularRootPath,realPath; 
    		HttpServletRequest httpRequest = (HttpServletRequest) request;
    		HttpServletResponse httpResponse=(HttpServletResponse)response;
    		ServletContext context = httpRequest.getServletContext();
    		destination =httpRequest.getServletPath();
    		realPath =context.getRealPath(destination);
    		angularRootPath="";
    		File f = new File(realPath);
    		if (f.exists()) {
    			chain.doFilter(request, response);
    		} else {
    			FilterRegistration fr= context.getFilterRegistration(this.getClass().getName());
    			for (String mapping: fr.getUrlPatternMappings()) {
    				mapping=mapping.replace("/*", "");
    				if (destination.indexOf(mapping)>-1) {
    					angularRootPath=mapping;
    					break;
    				}
    			}
    			if (angularRootPath.equals("")) {
    				httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
    			} else {
    				filterConfig.getServletContext().getRequestDispatcher(angularRootPath+"/index.html").forward(request, response);
    			}
    		}
    		f=null;		
    	}
    
    	/**
    	 * @see Filter#init(FilterConfig)
    	 */
    	public void init(FilterConfig fConfig) throws ServletException {
    		this.filterConfig=fConfig;
    	}
    
    }
    
  8. 右鍵點選這個project, 點選"Run as" ,再點選"Run on Server", 瀏覽器應該出現以下畫面:

  9. 瀏覽http://localhost:8080/DemoWeb/frontEnd/, 瀏覽器應該出現以下畫面:
  10. 點選"Go To Admin. Page" 連結,瀏覽器應該出現以下畫面:
    如果出現"admin works!" 字樣,即是設定成功了。

相關的source code 可以在這裡下載。

本篇發表於 電腦和網際網路。將永久鏈結加入書籤。

發表留言