開發(fā)模式的介紹 在Web開發(fā)模式中,有兩個主要的開發(fā)結構,稱為模式一(Mode I)和模式二(Mode II)
首先我們來理清一些概念吧:
DAO(Data Access Object):主要對數據的操作,增加、修改、刪除等原子性操作。 Web層:界面+控制器,也就是說JSP【界面】+Servlet【控制器】 Service業(yè)務層:將多個原子性的DAO操作進行組合,組合成一個完整的業(yè)務邏輯 控制層:主要使用Servlet進行控制 數據訪問層:使用DAO、Hibernate、JDBC技術實現對數據的增刪改查 JavaBean用于封裝數據,處理部分核心邏輯,每一層中都用到! 模式一 模式一指的就是在開發(fā)中將顯示層、控制層、數據層的操作統(tǒng)一交給JSP或者JavaBean來進行處理 !
模式一有兩種情況:
完全使用JSP做開發(fā) 優(yōu)點: 開發(fā)速度賊快,只要寫JSP就行了,JavaBean和Servlet都不用設計! 小幅度修改代碼方便,直接修改JSP頁面交給WEB容器就行了,不像Servlet還要編譯成.class文件再交給服務器!【當然了,在ide下開發(fā)這個也不算是事】 缺點: 程序的可讀性差、復用性低、代碼復雜!什么jsp代碼、html代碼都往上面寫,這肯定很難閱讀,很難重用! 使用JSP+JavaBean做開發(fā) 優(yōu)點: 程序的可讀性較高,大部分的代碼都寫在JavaBean上,不會和HTML代碼混合在一起,可讀性還行的 。可重復利用高,核心的代碼都由JavaBean開發(fā)了,JavaBean的設計就是用來重用、封裝,大大減少編寫重復代碼的工作! 缺點: 沒有流程控制,程序中的JSP頁面都需要檢查請求的參數是否正確,異常發(fā)生時的處理。顯示操作和業(yè)務邏輯代碼工作會緊密耦合在一起的!日后維護會困難 應用例子: 我們使用JavaBean+JSP開發(fā)一個簡易的計算器吧,效果如圖下 :
public class Calculator {
private double firstNum;
private double secondNum;
private char Operator =
'+' ;
private double result;
public void calculate () {
switch (
this .Operator) {
case '+' :
this .result =
this .firstNum +
this .secondNum;
break ;
case '-' :
this .result =
this .firstNum -
this .secondNum;
break ;
case '*' :
this .result =
this .firstNum *
this .secondNum;
break ;
case '/' :
if (
this .secondNum ==
0 ) {
throw new RuntimeException(
"除數不能為0" );}
this .result =
this .firstNum /
this .secondNum;
break ;
default :
throw new RuntimeException(
"傳入的字符非法!" );}}
public double getFirstNum () {
return firstNum;}
public void setFirstNum (
double firstNum) {
this .firstNum = firstNum;}
public double getSecondNum () {
return secondNum;}
public void setSecondNum (
double secondNum) {
this .secondNum = secondNum;}
public char getOperator () {
return Operator;}
public void setOperator (
char operator ) {Operator =
operator ;}
public double getResult () {
return result;}
public void setResult (
double result) {
this .result = result;}}
<%--開發(fā)用戶界面--%> <form action ="/zhongfucheng/1.jsp" method ="post" > <table border ="1" > <tr > <td colspan ="2" > 簡單計數器
</td > <td > </td > </tr > <tr > <td > 第一個參數:
</td > <td > <input type ="text" name ="firstNum" > </td > </tr > <tr > <td > 運算符
</td > <td > <select name ="operator" > <option value ="+" > +
</option > <option value ="-" > -
</option > <option value ="*" > *
</option > <option value ="/" > /
</option > </select > </td > </tr > <tr > <td > 第二個參數:
</td > <td > <input type ="text " name ="secondNum" > </td > </tr > <tr > <td colspan ="2" > <input type ="submit" value ="提交" > </td > <td > </td > </tr > </table > </form >
獲取得到顯示頁面提交的參數,調用JavaBean的方法,最后輸出結果! <%<jsp:useBean
id =
"calculator" class =
"domain.Calculator" scope=
"page" /><%<jsp:setProperty
name =
"calculator" property =
"*" /><%<jsp:scriptlet>calculator.calculate();</jsp:scriptlet><%<c:out value=
"計算得出的結果是:" /><jsp:getProperty
name =
"calculator" property =
"firstNum" /><jsp:getProperty
name =
"calculator" property =
"operator" /><jsp:getProperty
name =
"calculator" property =
"secondNum" /><c:out value=
"=" /><jsp:getProperty
name =
"calculator" property =
"result" />
開發(fā)這個簡易的計算器,只用了一個JSP頁面和一個JavaBean完成!
總的來說,Mode I 適合小型的開發(fā),復雜程序低的開發(fā),因為Mode I 的特點就是開發(fā)速度快,但在進行維護的時候就要付出更大的代價!
模式二 Mode II 中所有的開發(fā)都是以Servlet為主體展開的,由Servlet接收所有的客戶端請求,然后根據請求調用相對應的JavaBean,并所有的顯示結果交給JSP完成!,也就是俗稱的MVC設計模式!
MVC設計模式: - 顯示層(View):主要負責接受Servlet傳遞的內容,調用JavaBean,將內容顯示給用戶 - 控制層(Controller):主要負責所有用戶的請求參數,判斷請求參數是否合法,根據請求的類型調用JavaBean,將最終的處理結果交給顯示層顯示! - 模型層(Mode):模型層包括了業(yè)務層,DAO層。
應用例子: 我們使用MVC模式開發(fā)一個簡單的用戶登陸注冊的案例吧!作為一個簡單的用戶登陸注冊,這里就直接使用XML文檔當作小型數據庫吧 !
①搭建開發(fā)環(huán)境 導入相對應的開發(fā)包 創(chuàng)建程序的包名 創(chuàng)建xml文件,當做小型的數據庫
②開發(fā)實體User private int id;private String username;private String password;private String email;private Date birthday; ③開發(fā)dao public User
find (String username, String password) {InputStream inputStream = UserImplXML.class.getClassLoader().getResourceAsStream(
"user.xml" );SAXReader saxReader =
new SAXReader();
try {Document document = saxReader.read(path);Element element = (Element) document.selectSingleNode(
"//user[@username='" + username +
"' and@password='" + password +
"']" );
if (element ==
null ) {
return null ;}User user =
new User();user.setId(Integer.parseInt(element.attributeValue(
"id" )));user.setUsername(element.attributeValue(
"username" ));user.setPassword(element.attributeValue(
"password" ));user.setEmail(element.attributeValue(
"email" ));SimpleDateFormat simpleDateFormat =
new SimpleDateFormat(
"yy-MM-dd" );Date birthday = simpleDateFormat.parse(element.attributeValue(
"birthday" ));user.setBirthday(birthday);
return user;}
catch (DocumentException e) {e.printStackTrace();
throw new RuntimeException(
"初始化時候出錯啦!" );}
catch (ParseException e) {e.printStackTrace();
throw new RuntimeException(
"查詢的時候出錯啦!" );}}
做完一個功能,最好就測試一下,看有沒有錯誤再繼續(xù)往下寫! private String username = "zhongfucheng" private String password = "123" @Testpublic void testLogin() {UserImplXML userImplXML = new UserImplXML()User user = userImplXML.find (username, password)System.out .println (user.getBirthday ())System.out .println (user.getEmail ())System.out .println (user.getId ())System.out .println (user.getUsername ())System.out .println (user.getPassword ())}
3.2注冊功能
public void register (User user) {String path = UserImplXML.class.getClassLoader().getResource(
"user.xml" ).getPath();
try {SAXReader saxReader =
new SAXReader();Document document = saxReader.read(path);Element newElement = DocumentHelper.createElement(
"user" );newElement.addAttribute(
"id" , String.valueOf(user.getId()));newElement.addAttribute(
"username" , user.getUsername());newElement.addAttribute(
"email" , user.getEmail());newElement.addAttribute(
"password" , user.getPassword());SimpleDateFormat simpleDateFormat =
new SimpleDateFormat(
"yy-MM-dd" );String date = simpleDateFormat.format(user.getBirthday());newElement.addAttribute(
"birthday" ,date);document.getRootElement().add(newElement);OutputFormat outputFormat = OutputFormat.createPrettyPrint();outputFormat.setEncoding(
"UTF-8" );XMLWriter xmlWriter =
new XMLWriter(
new FileWriter(path),outputFormat);xmlWriter.write(document);xmlWriter.close();}
catch (DocumentException e) {e.printStackTrace();
throw new RuntimeException(
"注冊的時候出錯了!!!" );}
catch (IOException e) {e.printStackTrace();
throw new RuntimeException(
"注冊的時候出錯了!!!" );}}
@Test public void testRegister () {UserImplXML userImplXML = new UserImplXML();User user = new User(10 , "nihao" , "123" , "sina@qq.com" , new Date());userImplXML.register(user);} 注意!測試的結果是在classes目錄下的user.xml文件查詢的 !因為我們是用Test來測試代碼,讀取XML文件時使用的是類裝載器的方法,在編譯后,按照WEB的結構目錄,XML文件的讀寫是在WEB-INF的classes目錄下的!
DAO的實現已經開發(fā)完成了,接下來我們就對DAO的實現進行抽取。【當然了,也可以先寫DAO再寫DAO的實現】
④開發(fā)service層 service層的開發(fā)就非常簡單了!上面已經說了,service層就是:將多個原子性的DAO操作進行組合,組合成一個完整的業(yè)務邏輯 。簡單來說:對web層提供所有的業(yè)務服務的 !
在邏輯代碼不是非常復雜的情況下,我們可以沒有service層的 ,這里還是演示一下吧!
public class UserServiceXML {UserDao userImplXML = new UserImplXML();public void register (User user) {userImplXML.register(user);}public void login (String username, String password) {userImplXML.find(username, password);}}
⑤開發(fā)web層 5.1我們來先做注冊的界面吧! public class RegisterUIServlet extends javax .servlet .http .HttpServlet {protected void doPost (javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException, IOException {request.getRequestDispatcher(
"/WEB-INF/register.jsp" ).forward(request, response);}
protected void doGet (javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response)
throws javax.servlet.ServletException, IOException {
this .doPost(request, response);}}
<h1 > 歡迎來到注冊界面!
</h1 > <%--提交給處理注冊的處理Servlet--%> <form method ="post" action ="${pageContext.request.contextPath}/RegisterServlet" > <table > <%--對于id來講,是服務器分配的!不需要用戶自己輸入--%> <tr > <td > 用戶名
</td > <td > <input type ="text " name ="username" > </td > </tr > <tr > <td > 密碼
</td > <td > <input type ="text" name ="password" > </td > </tr > <tr > <td > 確認密碼
</td > <td > <input type ="text" name ="password" > </td > </tr > <tr > <td > 郵箱
</td > <td > <input type ="text" name ="email" > </td > </tr > <tr > <td > 生日
</td > <td > <input type ="text " name ="birethday" > </td > </tr > <tr > <td > <input type ="submit" value ="提交" > </td > <td > <input type ="reset" value ="重置!" > </td > </tr > </table >
</form >
接下來,我們要開發(fā)處理用戶注冊提交的Servlet //首先要接受Parameter的參數,封裝到User里面去String username = request.getParameter(
"username" );String password = request.getParameter(
"password" );//......如果參數過多,我們就要寫好多好多類似的代碼了
... 此時,我們應該想起反射機制中的BeanUtils開發(fā)包..為了更好地重用,我就將它寫成一個工具類 ! public static <T> T request2Bean(HttpServletRequest httpServletRequest, Class <T > tClass ) {try {T bean = tClass.newInstance();Enumeration enumeration = httpServletRequest.getParameterNames();while (enumeration.hasMoreElements()) {String name = (String) enumeration.nextElement();String value = httpServletRequest.getParameter(name);BeanUtils.setProperty(bean, name, value);}return bean;} catch (Exception e) {e.printStackTrace();throw new RuntimeException("封裝數據到Bean對象中出錯了!" );}}
經過我們測試,日期不能直接封裝到Bean對象中,會直接報出異常 !
ConvertUtils.
register (
new DateLocaleConverter(), Date.
class );
還有一個問題,用戶的id不是自己輸入的,是由程序生成的。我們避免id的重復,就使用UUID生成用戶的id吧! 為了更好的重用,我們也把它封裝成一個方法! public static int makeId () {return Integer.parseInt(UUID.randomUUID().toString());}
好的,我們來測試一下吧!以下是RegisterServlet的代碼 User user = WebUtils
.request 2Bean(request, User
.class )user
.setId (WebUtils
.makeId ())//調用service層的注冊方法,實現注冊ServiceBussiness serviceBussiness = new UserServiceXML()serviceBussiness
.register (user)
上面的代碼是不夠完善的(沒有校驗用戶輸入的信息、注冊成功或失敗都沒有給出提示..等等)
下面,我們來校驗用戶輸入的信息吧,如果用戶輸入的信息不合法,就直接跳轉回注冊的界面 。
剛才我們是用BeanUtils把Parameter的信息全部直接封裝到User對象中,但現在我想要驗證用戶提交表單的數據,也應該把表單的數據用一個對象保存著【面向對象的思想、封裝、重用】
流程是這樣子的:當用戶提交表單數據的時候,就把表單數據封裝到我們設計的表單對象上,調用表單對象的方法,驗證數據是否合法 !
好了,我們來開發(fā)一個表單的對象吧,最重要的是怎么填寫validate()方法! !
public class FormBean {
private String username;
private String password;
private String password2;
private String email;
private String birthday;
public boolean
validate () {
return false ;}
}
public boolean
validate () {
if (
this .username ==
null ||
this .username.trim().equals(
"" )) {
return false ;}
else {
if (!
this .username.matches(
"[a-zA-Z]{3,8}" )) {
return false ;}}
if (
this .password ==
null ||
this .password.trim().equals(
"" )) {
return false ;}
else {
if (!
this .password.matches(
"\\d{3,8}" )) {
return false ;}}
if (
this .password2 !=
null && !
this .password2.trim().equals(
"" )) {
if (!
this .password2.equals(
this .password)) {
return false ;}}
if (
this .email !=
null && !
this .email.trim().equals(
"" )) {
if (!
this .email.matches(
"\\w+@\\w+(\\.\\w+)+" )) {System.
out .println(
"郵箱錯誤了!" );
return false ;}}
if (
this .birthday !=
null && !
this .birthday.trim().equals(
"" )) {
try {DateLocaleConverter dateLocaleConverter =
new DateLocaleConverter();dateLocaleConverter.convert(
this .birthday);}
catch (Exception e) {System.
out .println(
"日期錯誤了!" );
return false ;}}
return true ;}
FormBean formBean = WebUtils.request2Bean(request, FormBean.class );if (formBean.validate()==false ){request.getRequestDispatcher("/WEB-INF/register.jsp" ).forward(request, response);return ;}try {User user = WebUtils.request2Bean(request, User.class );user.setId(WebUtils.makeId());ServiceBussiness serviceBussiness = new UserServiceXML();serviceBussiness.register (user);} catch (Exception e) {e.printStackTrace();}
接下來我們測試一下吧!將所有的信息都按照規(guī)定的輸入!
它拋出了錯誤!原因也非常簡單:表單數據提交給Servlet,Servlet將表單的數據(Parameter中的數據)用BeanUtils封裝到User對象中,當封裝到日期的時候,發(fā)現日期為null,無法轉換成日期對象!
那我們現在要怎么解決呢?
首先我們要明確:因為我們在設定的時候,已經允許了email和birthday可以為空,那么在DAO層就應該有相應的邏輯判斷email和birthday是否為空 !
if (user. getEmail() == null ) {newElement. addAttribute("email" , "" );} else {newElement. addAttribute("email" , user. getEmail());}if (user. getBirthday() != null ) {SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd" );String date = simpleDateFormat. format(user. getBirthday());newElement. addAttribute("birthday" , date );} else {newElement. addAttribute("birthday" , "" );}
解決辦法:
Parameter中的數據如果是”“,我就不把數據封裝到User對象中,執(zhí)行下一次循環(huán)! public static <T> T
request2Bean (HttpServletRequest httpServletRequest, Class<T> tClass) {
try {T bean = tClass.newInstance();Enumeration enumeration = httpServletRequest.getParameterNames();ConvertUtils.register(
new DateLocaleConverter(), Date.class);
while (enumeration.hasMoreElements()) {String name = (String) enumeration.nextElement();String
value = httpServletRequest.getParameter(name);
if (
value ==
"" ) {
continue ;}
else {BeanUtils.setProperty(bean, name,
value );}}
return bean;}
catch (Exception e) {e.printStackTrace();
throw new RuntimeException(
"封裝數據到Bean對象中出錯了!" );}}
將數據封裝到User對象中還有另外一個辦法:
我們知道BeanUtils有個copyProperties()方法,可以將某個對象的成員數據拷貝到另外一個對象的成員變量數據上(前提是成員變量的名稱相同!) 我們FormBean對象的成員變量名稱和User對象的成員變量的名稱是一致的 !并且,前面在驗證的時候,我們已經把Parameter中帶過來的數據封裝到了FormBean對象中了,所以我們可以使用copyProperties()方法! 使用該方法時,值得注意的是:第一個參數是拷貝到哪一個對象上(也就是User對象),第二個參數是被拷貝的對象(也就是formbean對象),口訣:后拷前….不要搞混了!!!!!(我就是搞混了,弄了很久…)
FormBean formBean = WebUtils.request2Bean(request, FormBean.
class );
if (formBean.validate()==
false ){request.getRequestDispatcher(
"/WEB-INF/register.jsp" ).forward(request, response);
return ;}
try {User user1 = WebUtils.request2Bean(request,User.
class );user1.setId(WebUtils.makeId());ServiceBussiness serviceBussiness =
new UserServiceXML();serviceBussiness.
register (user1);}
catch (Exception e) {e.printStackTrace();}
現在還有問題,如果我填寫信息不合法,提交給服務器驗證以后,服務器應該告訴用戶哪個信息不合法,而不是直接把跳轉回注冊界面,把所有的信息全部清空,讓用戶重新填寫!
我們應該這樣做:當發(fā)現用戶輸入的信息不合法時,把錯誤的信息記錄下來,等到返回注冊頁面,就提示用戶哪里出錯了!
private String username;
private String password;
private String password2;
private String email;
private String birthday;
private HashMap<String, String> error =
new HashMap<>();
public boolean validate () {
if (
this .username ==
null ||
this .username.trim().equals(
"" )) {error.put(
"username" ,
"用戶名不能為空,并且要是3-8的字符" );
return false ;}
else {
if (!
this .username.matches(
"[a-zA-Z]{3,8}" )) {error.put(
"username" ,
"用戶名不能為空,并且要是3-8的字符" );
return false ;}}
if (
this .password ==
null ||
this .password.trim().equals(
"" )) {error.put(
"password" ,
"密碼不能為空,并且要是3-8的數字" );
return false ;}
else {
if (!
this .password.matches(
"\\d{3,8}" )) {error.put(
"password" ,
"密碼不能為空,并且要是3-8的數字" );
return false ;}}
if (
this .password2 !=
null && !
this .password2.trim().equals(
"" )) {
if (!
this .password2.equals(
this .password)) {error.put(
"password2" ,
"兩次密碼要一致" );
return false ;}}
if (
this .email !=
null && !
this .email.trim().equals(
"" )) {
if (!
this .email.matches(
"\\w+@\\w+(\\.\\w+)+" )) {error.put(
"email" ,
"郵箱不合法!" );
return false ;}}
if (
this .birthday !=
null && !
this .birthday.trim().equals(
"" )) {
try {DateLocaleConverter dateLocaleConverter =
new DateLocaleConverter();dateLocaleConverter.convert(
this .birthday);}
catch (Exception e) {error.put(
"birthday" ,
"日期不合法!" );
return false ;}}
return true ;}
if (formBean.validate()==
false ){request.setAttribute(
"formbean" , formBean);request.getRequestDispatcher(
"/WEB-INF/register.jsp" ).forward(request, response);
return ;}
做到這里,還是有丟丟的問題,我們不應該把用戶輸入的數據全部清空的!你想想,如果用戶注冊需要輸入多個信息,僅僅一個出錯了,就把全部信息清空,要他重新填寫,這樣是不合理的!
我們在各個的輸入項中使用EL表達式回顯數據就行了 !
還沒有完善,細心的朋友可以發(fā)現,上面圖的日期也是錯誤的,但是沒一次性標記出來給用戶!要改也十分簡單:在驗證的時候,不要先急著return false 用一個布爾型變量記住,最后返回布爾型的變量即可
無論注冊成功還是失敗都需要給用戶一個友好界面的!
5.2登陸界面 登陸和注冊是類似的,我們按著注冊的步驟來寫就對了!
首先寫一個提供登陸界面的Servlet
//直接跳轉到登陸界面request.getRequestDispatcher ("/WEB-INF/login.jsp" ).forward (request, response)
<h1 > 這是登陸界面
</h1 > <form action ="${pageContext.request.contextPath}/LoginServlet" method ="post" > <table > <tr > <td > 用戶名
</td > <td > <input type ="text" name ="username" > </td > </tr > <tr > <td > 密碼
</td > <td > <input type ="password" name ="password" > </td > </tr > <tr > <td > <input type ="submit" value ="提交" > </td > <td > <input type ="reset" name ="重置" > </td > </tr > </table >
</form >
String username = request.getParameter(
"username" );
String password = request.getParameter(
"password" );
try {ServiceBussiness serviceBussiness =
new UserServiceXML();User user = serviceBussiness.login(username, password);
if (user ==
null ) {request.setAttribute(
"message" ,
"用戶名或密碼是錯的" );}
else {request.setAttribute(
"message" ,
"登陸成功" );}}
catch (Exception e) {e.printStackTrace();request.setAttribute(
"message" ,
"登陸失敗咯" );}request.getRequestDispatcher(
"/message.jsp" ).forward(request, response);
5.3把注冊和登陸都掛在首頁上 <h1 > 這是首頁!
</h1 > <a href ="${pageContext.request.contextPath}/LoginUIServlet" > 登陸
</a > <a href ="${pageContext.request.contextPath}/RegisterUIServlet" > 注冊
</a > </body >
轉載于:https://www.cnblogs.com/zhong-fucheng/p/7203040.html
總結
以上是生活随笔 為你收集整理的Web开发模式【Mode I 和Mode II的介绍、应用案例】 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。