上一篇講完了不止于CRUD的設計,本篇就在新設計的基礎上實現用戶登錄,在實現之前,貓哥先放一張數據庫結構的截圖(之前的設計竟然忘了學生選課表student_lesson,好尷尬啊…所以此處重放)
step1,用戶登錄頁面代碼如下,需要注意的是點擊登錄后提交到/HomeworkSystem/ActionServlet?method=login&entityType=User
method=login表示登錄動作 entityType=User表示動作相關對象類別是User
step2:根據web.xml配置,ActionServlet負責處理該請求,代碼如下,注意注釋部分的解釋內容:
package servlet;import java.io.IOException;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import action.support.Action;import action.support.ActionContext;import exception.MyException;import java.util.Iterator;import java.util.Map;//ActionServlet作為整個項目唯一的Servletpublic class ActionServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response);//doGet與doPost一樣處理 } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //輸入輸出格式設置 response.setContentType("text/html"); request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); //根據request用戶輸入信息創建不同的ActionContext(Action上下文) ActionContext context=ActionController.assemblyActionContext(request); //根據不同的ActionContext創建不懂的action動作 Action action=ActionController.dispatchAction(context); try { context=action.execute();//執行動作并返回結果 } catch (MyException ex) {//如果有異常,跳轉異常提示頁面 request.setAttribute("tsession")){ request.getSession().setAttribute(key.toString(), val); }else{ request.setAttribute(key.toString(), val); } } } //跳轉到index.jsp主頁面,注意 actionUrl指向頁面顯示在index.jsp右邊內容區域 request.getRequestDispatcher("/index.jsp").forward(request,response); }}step3,ActionServlet中有兩個重要方法,這兩個方法實際上就定義了動作路由,前一個方法定義了如何從用戶輸入獲取Action需要的上下文環境,后一個方法則從上下文環境自動生成對應的動作。當正式編程時,每當定義一個新的動作類處理一類動作時,都要從ActionController類的這兩個方法中進行注冊對應的上下文生成邏輯和匹配動作邏輯。
//根據request用戶輸入信息創建不同的ActionContext(Action上下文)ActionContext context=ActionController.assemblyActionContext(request);//根據不同的ActionContext創建不懂的action動作Action action=ActionController.dispatchAction(context);OK,此時我們要進行的是登錄動作,method=login。所以ActionController中可添加如下代碼,注意注釋中的解釋內容。
package servlet;import inter.IOperation;import java.util.*;import javax.servlet.http.HttpServletRequest;import entity.*;import factory.EntityFactory;import factory.OperationFactory;import action.*;import action.support.Action;import action.support.ActionContext;/** * 實質的控制器 * @author 貓哥 * @date 2017.2.11 * 一定注意該類是整個控制邏輯的核心,每當有新的Action來了,需要從本類進行類似“注冊”的動作,而且必須保證 * createAction與assemblyActionContext正確的呼應(對應)關系 */public class ActionController { /*assembly裝配的意思,裝配ActionContext即裝配動作的上下文,上下文的意思就是環境 一定注意本方法不管如何執行,只關心需要執行時候需要哪些參數*/ public static ActionContext assemblyActionContext(HttpServletRequest request){ ActionContext context=new ActionContext(); //裝配兩個必備參數 context.setOperationType(request.getParameter("method")); context.setEntityType(request.getParameter("entityType")); //剩下的就是根據需要裝配了 if(context.getOperationType().equals("login")){ //登錄時間,需要攜帶用戶輸入的用戶名、密碼 Map<String,Object> map=new HashMap<String,Object>(); map.put("userId", request.getParameter("userId")); map.put("userPassword", request.getParameter("userPassword")); context.setInputParams(map); } return context; } /*dispatch的意思是調度,分派 一定注意本方法只關心將context中請求派給哪個Action處理 為了保證呼應,可先直接將上面if段拷貝,然后修改內容*/ public static Action dispatchAction(ActionContext context){ if(context.getOperationType().equals("login")){ return new LoginAction(context); } return null; }}由此可見針對login動作,ActionController生成了含userId和userPassword信息的上下文,且定義了該上下文對應的Action為LoginAction(context)。
step4,這樣動作LoginAction開始執行。
package action;import java.util.Date;import java.util.HashMap;import java.util.Map;import operation.UserOperation;import action.support.Action;import action.support.ActionContext;import util.Constant;import entity.User;import exception.MyException;import factory.OperationFactory;public class LoginAction extends Action{ public LoginAction(ActionContext context){ super(context); } @Override public ActionContext execute() throws MyException { UserOperation oper=(UserOperation)OperationFactory.createOperation(context.getEntityType()); String inputUserId=(String)context.getInputParams().get("userId"); String inputUserPassword=(String)context.getInputParams().get("userPassword"); User realUser=(User)oper.selectById(Integer.parseInt(inputUserId)); if(realUser!=null&&realUser.getUserPassword().equals(inputUserPassword)){ //設置返回參數back Map<String,Object> back=new HashMap<String,Object>(); //登錄用戶,一定注意如果需要Servlet接收到返回context時將對應量放入session域,則命名為session.... back.put("sessionUser", realUser); //登錄用戶角色對應菜單 back.put("sessionRoleMenu", Constant.RoleMenu.get(realUser.getUserRole().getRoleName())); context.setOutputParams(back); context.setActionUrl("tip.jsp"); return context; } else{ throw new MyException(new Date(),"LoginAction Error","登錄失??!"); } }}到此處再結合ActionServlet中處理context.getOutputParams()的邏輯就好理解了,返回值如果需要放入session域,那么action中命名時就加上session。如果放入request域,那就不要使用session字樣的命名。
Map<String,Object> map=context.getOutputParams(); if(map!=null){ Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Object key = entry.getKey(); Object val = entry.getValue(); if(key.toString().startsWith("session")){ request.getSession().setAttribute(key.toString(), val); }else{ request.setAttribute(key.toString(), val); } } }step5,好的,角色菜單信息依然放在Constant中:
package util;import java.util.HashMap;public class Constant {//保存常量信息 //roleMenu用于保存角色及對應的菜單信息 public static HashMap<String,String[][]> RoleMenu=new HashMap<String,String[][]>(); //pageSize用于保存不同實體列表頁面顯示實體個數信息(每頁多少個) public static HashMap<String,String> PageSize=new HashMap<String,String>(); //使用static代碼塊對roleMenu進行初始化 static{ //注意,二位數組中的每一組表示一個菜單的信息,又通過map建立了角色名和菜單直接的對應關系 RoleMenu.put("校長", new String[][]{ {"人員管理","view","User"},//由具體的地址,變為抽象的參數 {"課程管理","view","Course"} }); RoleMenu.put("教師", new String[][]{}); RoleMenu.put("學生", new String[][]{}); //初始化頁面列表個數 PageSize.put("Course", "10"); PageSize.put("Job", "10"); PageSize.put("Lesson", "10"); PageSize.put("Role", "10"); PageSize.put("User", "10"); PageSize.put("Work", "10"); } }step6,最后是登錄成功后的index.jsp頁面代碼及其相關CSS文件index.css:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%@ taglib 字體大小12px,宋體*/ *{ margin:0px; padding:0px; font-size:12px; font-family:"宋體"; } /*整個body區域背景色為#F5F5F5,這個很簡單,自己下載個取色器,找個漂亮的網頁,取個顏色就行*/ body { background-color: #FCFCFC; } /*在top、left、right外面套用一層main是為了控制寬度,并且整體居中*/ #main{ width:1000px; margin:0px auto; } /*寬度占滿它爹的寬度,高度64px是瞎試的,不好看再調整,貓哥喜歡用16px、32px、64px、128px這些,你懂的。 背景色貓哥繼續取色器 line-height表示文字占用的高度,它也是64那就是文字占用高度跟top區域高度是一樣的嘛,所以文字就居中了*/ #top{ width:100%; height:64px; background-color:#000000; line-height:64px; } /*文字顏色取色器,標題部分啊文字用微軟雅黑,大氣!*/ #top_title{ line-height:64px; font-family:"微軟雅黑"; color:#FFFFFF; float:left; font-size:32px; margin-left:16px; } /*顏色依然是自己取色的*/ #top_info{ color:#71777D; float:right; line-height:64px; font-size:16px; margin-right:16px; } /*寬度占200px差不多了吧 float表示漂浮,left的話就是靠左了,所以這個left區域就得靠左飄飄了 內部的東西跟邊距有點距離好看點,暫時定為10px,上下左右都是哦*/ #left{ width:200px; height:536px;/*貓哥認為600-64=536*/ float:left; background-color:#EEEEEE; padding:10px; } /*調整id=left的div中的ul標簽下的li標簽的樣式為上邊距10px,左邊距15px*/ #left ul li{ margin:10px 0px 0px 15px; } /*注意逗號表示同時設置兩組對象的CSS屬性 a:link表示未訪問的鏈接,a:visited表示已訪問的鏈接,顏色憑愛好了*/ #left a:link, #left a:visited { color: #333333; text-decoration:none;/*不要下劃線*/ } /*a:hover表示鼠標懸停的鏈接,a:active表示被選擇的鏈接*/ #left a:hover, #left a:active { color: #0AA770; text-decoration:none; } /*同理right向右飄*/ #right{ width:760px;/*1000-200-10*4=760,此處一定要注意padding的內容會拓寬div整體寬度,有志于前端的可以專門去研究下*/ min-width:600px; height:536px;/*貓哥認為600-64=536*/ float:right; background-color:#FFFFFF; padding:10px; }新聞熱點
疑難解答