單體式客服系統通常整合預約、留言、訊息等功能於單一應用程式中。本文將以 Java 和 Spring 為例,說明如何設計和建置此類別系統,並探討其在實際應用中的優缺點。首先,我們會介紹預約服務的 getAvailableDates 和 saveAppointment API,以及留言板服務的 getMessage API,並提供程式碼範例說明其實作方式。接著,會說明如何組態資料函式庫連線、使用 Ant 建置專案,以及佈署至 AWS EC2 的流程。這些步驟涵蓋了單體式應用程式從開發到佈署的完整生命週期。
單體式客服系統應用案例研究
預約服務
預約服務允許使用者根據可用時間和日期預約客服專家。此服務提供以下功能:
getAvailableDates:根據給定的請求檢索可用的日期和時間。saveAppointment:為選定的可用時間和日期儲存預約。
getAvailableDates 服務
此服務檢索特定時間段內可用的日期和時間。
- Context:AppointmentService/getAvailableDates
- Method:POST
- Consumes:application/xml、application/json
- Produces:application/json
- Input:HttpHeaders、AppointmentAvailableDateRequest
- Output:AppointmentAvailableDateResponse
@Override
@POST
@Consumes({"application/xml", "application/json"})
@Produces({"application/json"})
@Path("/getAvailableDates/")
public AppointmentAvailableDateResponse getAvailableDates(
@Context HttpHeaders headers,
AppointmentAvailableDateRequest request) {
// 實作 DAO 邏輯
}
內容解密:
@POST表示此服務使用 HTTP POST 方法。@Consumes指定服務可接受的輸入格式,包括 XML 和 JSON。@Produces指定服務輸出的格式為 JSON。@Path定義服務的 URL 路徑。getAvailableDates方法根據請求檢索可用的日期和時間,並傳回相應的回應。
saveAppointment 服務
此服務儲存特定時間和日期的預約。
- Context:AppointmentService/saveAppointment
- Method:POST
- Consumes:application/xml、application/json
- Produces:application/json
- Input:HttpHeaders、TITLE、request
- Output:回應狀態(成功或失敗)
@Override
@POST
@Consumes({"application/xml", "application/json"})
@Produces({"application/json"})
@Path("/saveAppointment/")
public Response saveAppointment(
@Context HttpHeaders headers,
// 請求物件
) {
// 實作儲存預約邏輯
}
內容解密:
- 此服務使用 HTTP POST 方法儲存預約。
- 服務接受 XML 和 JSON 格式的輸入,並輸出 JSON 格式的回應。
saveAppointment方法儲存預約並傳回相應的回應狀態。
留言板服務
留言板服務提供使用者與客服專家之間的協作功能。該服務包含以下功能:
getMessage:根據給定的標題檢索留言。getAllMessage:檢索特定時間段內的所有留言。createMessage:儲存使用者提供的留言、問題或答案。
getMessage 服務
此服務根據給定的標題檢索留言、問題和答案。
- Context:MessageService/getMessage/{title}
- Method:GET
- Consumes:application/xml、application/json
- Produces:application/json
- Input:HttpHeaders、TITLE
- Output:回應狀態(成功或失敗)
@Override
@GET
@Consumes({"application/xml", "application/json"})
@Produces({"application/json"})
@Path("/getMessage/{title}")
public MessageViewResponse getMessage(
@Context HttpHeaders headers,
@PathParam("title") String title) throws ServiceInvocationException {
// 實作 DAO 邏輯
}
內容解密:
@GET表示此服務使用 HTTP GET 方法。@PathParam用於從 URL 路徑中提取標題引數。getMessage方法根據標題檢索留言並傳回相應的回應。
建置應用程式
現在,我們已經介紹了應用程式的架構、Web 服務和各種依賴項,接下來將下載程式碼、建置並執行它。
設定 Eclipse
我們使用 Eclipse IDE 進行開發,您可以選擇自己最舒適的 IDE。以下是設定 Eclipse 的步驟:
- 從 https://eclipse.org/downloads/index-developer.php 下載 Eclipse。
- 解壓縮下載的檔案,Eclipse 的先決條件是系統路徑中的 JRE。
- 雙擊 eclipse.exe。
- 在套件總管中右鍵點選並選擇「新建 Java 專案」,命名為 Helpdesk。
- 取消選取「使用預設位置」,瀏覽到您克隆程式碼的目錄,然後點選「開啟」。
建置應用程式
以下是建置應用程式並產生可佈署 WAR 檔案的步驟:
- 在建置 WAR 檔案之前,需要在 applicationContext.xml 檔案中組態資料函式庫。
- 在 Project Location/src/main/webapp/WEB-INF/applicationContext.xml 中找到 DataSource bean,並修改 url、username 和 password 屬性。
<!-- 資料函式庫組態範例 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/helpdesk"/>
<property name="username" value="your_username"/>
<property name="password" value="your_password"/>
</bean>
內容解密:
- 資料函式庫組態是建置應用程式的關鍵步驟。
- 需要根據實際資料函式庫環境修改 url、username 和 password 屬性。
單體式Helpdesk應用程式案例研究:建置與佈署
本章節將探討單體式Helpdesk應用程式的建置與佈署流程,涵蓋從環境組態到最終佈署的全過程。
資料來源組態
首先,我們需要組態資料來源以連線MySQL資料函式庫。以下是一個典型的Spring組態範例:
<bean id="DataSource" destroy-method="close"
class="org.apache.tomcat.jdbc.pool.DataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://<dbhost>:<dbport>/<dbname>" />
<property name="username" value="<Username>" />
<property name="password" value="<Password>" />
<property name="initialSize" value="5" />
<property name="maxActive" value="50" />
<property name="validationQuery" value="select 1 from dual" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="true" />
<property name="minIdle" value="0" />
<property name="minEvictableIdleTimeMillis" value="30000" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="30000" />
<property name="logAbandoned" value="true" />
<property name="maxWait" value="120000" />
</bean>
內容解密:
此組態定義了一個名為DataSource的Bean,使用Apache Tomcat的JDBC連線池來管理與MySQL資料函式庫的連線。主要屬性包括:
driverClassName和url:指定資料函式庫驅動程式和連線URL。username和password:資料函式庫登入憑證。initialSize和maxActive:初始化和最大活動連線數。validationQuery:驗證連線是否有效的SQL查詢。testWhileIdle和testOnBorrow:控制連線驗證時機。minIdle和minEvictableIdleTimeMillis:最小閒置連線數和連線可被收回的最短時間。removeAbandoned和logAbandoned:控制放棄連線的處理。
建置指令碼(Build.xml)組態
接下來,我們需要建立一個Ant建置指令碼(Build.xml)來編譯和封裝應用程式。
<project name="projects" default="jar" basedir=".">
<!-- 定義專案屬性 -->
<property name="src" location="src"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<!-- 編譯和封裝目標 -->
<target name="compile.individual" depends="init">
<javac includeantruntime="false" debug="true" compiler="javac1.6"
srcdir="${src}" destdir="${build}">
<classpath refid="project.classpath"/>
</javac>
</target>
<target name="jar.individual" depends="compile.individual">
<!-- 封裝JAR檔案 -->
<jar jarfile="${jar.location}/org-${ant.project.name}.jar" basedir="${build}"/>
</target>
<!-- WAR檔案封裝目標 -->
<target name="war" depends="init.war,copy.files">
<war destfile="dist/lib/helpdesk.war" webxml="src/main/webapp/WEB-INF/web.xml">
<fileset dir="src/main/webapp">
<exclude name="**/.svn"/>
</fileset>
<lib dir="src/main/webapp/WEB-INF/lib" />
<classes dir="${build}/classes" />
</war>
</target>
</project>
內容解密:
此Ant指令碼定義了編譯、封裝JAR和WAR檔案的目標。主要步驟包括:
- 編譯原始碼(
compile.individual目標)。 - 封裝JAR檔案(
jar.individual目標)。 - 複製必要檔案到指定目錄(
copy.files目標)。 - 封裝WAR檔案(
war目標),包含Web應用程式的組態和類別檔案。
佈署到AWS EC2
最後,我們將WAR檔案佈署到AWS EC2上的Tomcat伺服器。
安裝Tomcat 7和MySQL:
sudo apt-get install tomcat7sudo apt-get install mysql-server
啟動和管理服務:
sudo service tomcat7 start/stop/statussudo service mysql start/stop/status
建立資料函式庫和佈署WAR檔案:
- 在MySQL中建立名為
helpdesk的資料函式庫。 - 將WAR檔案透過Tomcat管理控制檯佈署到伺服器。
- 在MySQL中建立名為
內容解密:
佈署過程包括安裝必要的軟體、組態和管理服務、建立資料函式庫以及最終佈署應用程式。確保Tomcat和MySQL服務正確執行,並透過Tomcat管理控制檯佈署WAR檔案。
第 11 章:單體式 Helpdesk 應用程式案例研究
新需求與錯誤修復
想像一下,應用程式已經上線並為客戶提供服務,這標誌著軟體維護生命週期的開始。隨著時間的推移,將會有新的請求來更新或更改應用程式的功能,同時客戶也可能會發現一些錯誤。所有這些請求都需要更改程式碼和/或重建應用程式。讓我們來理解維護單體式應用程式所面臨的挑戰和所涉及的工作。
假設我們需要為檢視票據服務新增一個額外的引數,該引數對其他元件的依賴性非常有限或沒有依賴。透過以下程式碼,我們更改了票據請求:
public TicketResponse createHdTicket(
@Context HttpHeaders headers,
TicketRequest ticketRequest)
throws ServiceInvocationException{
以下程式碼允許我們在 Plain Old Java Object(POJO,即網頁模型)中新增一個新的屬性:
@Component
private String emailAddress;
@XmlElement
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
使用以下程式碼,我們可以在 DAO 層新增邏輯以從資料函式庫中取得該屬性:
private String saveToDatabase(TicketRequest ticketRequest){
//與現有的程式碼一起新增
ticket.setEmailAddress(ticketRequest.getEmailAddress());
}
內容解密:
createHdTicket方法:此方法負責建立一個新的幫助台票據。它接受HttpHeaders和TicketRequest物件作為輸入,並傳回一個TicketResponse物件。emailAddress屬性:在TicketRequest物件中增加了一個新的屬性emailAddress,用於儲存使用者的電子郵件地址。saveToDatabase方法:此方法負責將票據請求儲存到資料函式庫中。它從TicketRequest物件中取得emailAddress屬性,並將其儲存到資料函式庫中。
雖然程式碼變更看起來很簡單,但接下來需要做以下工作:
- 構建整個網頁應用程式:這意味著需要重新佈署整個應用程式。
- 進行迴歸測試:需要對整個應用程式進行迴歸測試,以確保其他功能仍然按預期工作。
- 解決錯誤和依賴問題。
- 佈署到測試環境並進行品質保證流程。
- 佈署到生產環境。
如果應用程式未以高用性(HA)模式佈署,則意味著將會發生停機時間,因為應用程式將被重新佈署。
所有這些步驟都增加了發布此次小幅變更所需的時間,並違背了敏捷開發的原則。這還不包括持續變更的情況,您可能需要建立新的程式碼分支並再次合併和測試。
面臨的其他挑戰
- 修復錯誤:每個錯誤修復都需要佈署整個構建版本,這意味著如果沒有適當的 HA 佈署架構,則可能導致系統停機。此外,根據所使用的系統開發生命週期(SDLC)方法論,這可能意味著在引入錯誤修復之前需要很長時間。對於關鍵錯誤,通常意味著建立和維護一個「熱修復」分支,這可能會使程式碼函式庫變得複雜,並在稍後造成合併問題。
- 更換應用程式元件:這是另一個需要對整個應用程式進行重構/重新實作的案例。假設組織希望使用雲端服務進行票據管理;目前應用程式的編寫方式很難將相關模組與應用程式解耦。
- 更換或新增新的技術堆積疊:在這種情況下,除非整個應用程式被重新實作,否則您無法自由選擇新模組/功能所需的技術。由於單體式架構,組織被迫使用所選擇的技術。
- 選擇性擴充套件:假設您希望擴充套件票據模組以適應使用模式。在這種情況下,由於應用程式元件緊密整合為單體式應用程式,因此擴充套件變得非常複雜。例如,僅分離票據模組就需要大量的程式碼重構、與獨立的票據系統整合、測試、新的佈署架構等。
- 處理故障:在單體式應用程式中,一個元件的故障可能會破壞整個應用程式。假設產品目錄服務關閉,這將阻止使用者提交新的工作票據。新的工作票據應該指示使用者遇到問題的產品,以便更好地路由票據和更快地解決問題。但是,產品目錄服務中的錯誤不應該阻止使用者建立票據本身,也就是說,它不應該使票據服務本身宕機。但是,鑑於單體式架構,如果產品目錄是一個必填欄位並且存在錯誤,使用者將在此階段卡住,即使他或她可以描述問題。
雖然對於我們的應用程式來說這些挑戰很大,但它們是當今數位世界中的基本需求。使用單體式方法解決這些問題變得非常昂貴和耗時。在接下來的兩章中,我們將討論如何透過微服務和容器來解決這些挑戰。