首页 > 编程 > JSP > 正文

JSP+Servlet培训班作业管理系统[13] -使用基于Action的后端(用户登录为例)

2019-11-06 07:00:06
字体:
来源:转载
供稿:网友

上一篇讲完了不止于CRUD的设计,本篇就在新设计的基础上实现用户登录,在实现之前,猫哥先放一张数据库结构的截图(之前的设计竟然忘了学生选课表student_lesson,好尴尬啊…所以此处重放) 这里写图片描述

step1,用户登录页面代码如下,需要注意的是点击登录后提交到/HomeworkSystem/ActionServlet?method=login&entityType=User method=login表示登录动作 entityType=User表示动作相关对象类别是User

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>login.jsp</title> </head> <body> <form id="mainForm" method="post" action="/HomeworkSystem/ActionServlet?method=login&entityType=User"> 请输入用户编号:<input type="text" name="userId" /> <br/> 请输入密码:<input type="passWord" name="userPassword"/> <br/> <input type="submit" value="登录"/> </form> </body></html>

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("tipInfo", ex.getInfo()); request.getRequestDispatcher("/tip.jsp").forward(request,response); } //设置返回页面 request.setAttribute("actionUrl",context.getActionUrl()); //取上下文中的返回值 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); } } } //跳转到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 PRefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!-- 使用c:标签需要添加本行代码 --><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <title>index.jsp</title> <link href="css/index.css" type="text/css" rel="stylesheet"/> </head> <body> <div id="main"> <div id="top"> <div id="top_title"> 猫哥培训班作业管理系统 </div><!-- 标题部分 --> <div id="top_info"> 欢迎您,尊敬的:${sessionUser.userName} </div><!-- 登录用户信息部分 --> </div><!-- top部分是标题栏 --> <div id="left"> <ul> <c:forEach items="${sessionRoleMenu}" var="menu"> <li> <a href="/HomeworkSystem/ActionServlet?method=${menu[1]}&entityType=${menu[2]}">${menu[0]}</a> </li> </c:forEach> </ul> </div><!-- left部分是菜单栏 --> <div id="right"> <c:if test="${empty actionUrl}"> 欢迎来到猫哥培训班管理系统 </c:if> <c:if test="${not empty actionUrl}"> <jsp:include page="${actionUrl}" flush="true"></jsp:include> </c:if> </div><!-- right部分是具体内容显示区 --> </div> </body></html> /*css/index.css*/ /*星号表示选择全部,设置外边距0,内边距0,字体大小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; }
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表