按照猫哥的一般习惯,做一个项目的顺序如下:
1,先搞定数据库
2,搞定Java Web项目基本结构,包括数据库相关操作类
3,开发Java Web各项功能
4,优化、改进
这个顺序呢,不直观,而且容易使人厌倦,非常无聊,是故,抛弃之。这次猫哥从看的见摸得着的网页出发,然后网页需要后台提供啥功能,就搞啥。最后后台需要数据库啥样,就弄啥样,用这样一个顺序实现培训班管理系统。为了方便记忆和理解,猫哥将内容分节,节名统一用从task:X-Y开始,X表示任务名称,Y表示任务步骤
。
task:1-1
,作为一个系统,首先就得提供登录功能。设计一个最简单的登录页面如下:
<%@ 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/LoginServlet">
请输入用户名:<input type="text" name="userName" />
<br/>
请输入密码:<input type="password" name="userPassword"/>
<br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
task:1-1注意点
1,文件为:WebRoot/login.jsp
2,注意编码保持utf-8
3,点击【登录】按钮后,表单内容被提交给/LoginServlet
task:1-2
,我们来编辑LoginServlet处理登录页面提交的登录请求吧。(猫哥使用的MyEclipse菜单新建的LoginServlet,自动生成了web.xml文件代码和LoginServlet类及方法,猫哥为了演示更加清晰,将演示必要代码)。
<?xml version="1.0" encoding="UTF-8"?><!-- web.xml文件内容 -->
<web-app version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>
</web-app>
package servlet;//在servlet包下
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public class LoginServlet extends HttpServlet {//用于处理登录请求的LoginServlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);//直接调用doPost方法处理get请求
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {//处理post请求
//设置输入输出格式、编码
response.setContentType("text/html");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
//获取用户在网页输入的用户名和密码
String userName=request.getParameter("userName");
String userPassword=request.getParameter("userPassword");
}
}
task:1-3
,现在,用户的登录请求抛给了我们的Servlet处理,此时的逻辑应该如下设计:
1,如果用户名或密码为空,提示用户输入。
2,如果用户名或密码错误,提示用户重新输入(注意此处用户名不存在也认为是输入错了即可)。
3,如果用户名和密码都正确,跳转到相应用户页面。
4,因为存在校长、教师、学生三种不同的角色,不同角色登录后页面显示内容不同(校长可以新增教师、学生,教师可以新增课程,学生可以提交作业,功能不同)。
根据以上讨论,我们至少知道我们需要用户的信息有:用户名,密码,角色,另外为了避免用户名重复,我们需要一个唯一标识id(就像QQ上网名可以重复,但是QQ号是唯一的)。此处我们先不管数据库(差不多什么样心里也有数了吧),先把用户这个实体类设计出来。
package entity;//在entity包下,注意了
public class User {
private int userId;
private String userName;
private String userPassword;
private String userRole;
//以后省略无聊的get set方法,自行补足
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
public String getUserRole() {
return userRole;
}
public void setUserRole(String userRole) {
this.userRole = userRole;
}
}
此处有一点需要注意,就是userRole这个玩意,也就是角色。如果角色确定了就三种(校长、教师、学生),且每种角色对应的功能固定,那么就直接private String userRole;对应数据库中的user_role列搞定(列值为校长、教师、学生三者之一)。如果要想系统拓展性更好,比如角色可能增加(副校长、教师又分班主任、助教..),那么可以将角色单独设计为一张表,而用户中的user_role指向角色表一条记录即可。此处我们采取这种先进理念(哈哈自吹自擂),所以实体类改为:
package entity;
public class User {
private int userId;
private String userName;
private String userPassword;
private Role userRole;
//自行补足get set
}
//邪恶的分界线
package entity;
public class Role {
private int roleId;
private String roleName;
//自行补足get set
}
task:1-4
,然后我们现在需要操作数据库了,但是猫哥想把数据库留到最后再实现(实在是大同小异没啥意思),那咋办那。好办,我们就像个八路军指挥官一样,三团上去干鬼子,至于三团怎么干鬼子,让三团长自己想办法,先把命令下去再说。我们建一个包command,用于向数据库下令,首先我们把登录相关的命令保存在LoginCommand类里面,代码如下:
package command;
public class LoginCommand {//从此处向数据库类下操作指令
}
结合task:1-3
中的需求分析,我们需要向LoginCommand 这个小团长(确实官职小,在程序设计的世界里,程序员就是最牛X的大官),下达检查登录指令
。这个指令描述如下:
指令:检查登录
动作:检查userName和userPassword是否正确
行动结果:失败:执行失败原因(无此人?信息错误?..)
行动结果:成功:把此人带来见我!我要根据他的能力(校长、教师、学生)给他安排工作。
这样一看,就简单了,这样设计就行:
package command;
import entity.User;
public class LoginCommand {//从此处向数据库类下操作指令
public User checkLogin(String userName,String userPassword) throws Exception{
if(userName.equals("")||userPassword.equals("")){
//抛出输入信息异常
}
User user=null;
try{
//从数据库中执行查询
}catch(Exception e){
//抛出数据库异常
}
return user;
}
}
好的,这样一看,我们后续只需要把执行用户查询的语句放在//从数据库中执行查询
处,就可以了。此处还有几个异常,需要处理,我们希望能把所有的异常信息统计起来,所以定义个自定义异常类如下:
package exception;
import java.util.Date;
public class MyException extends Exception{
private Date time;//记录异常发生时间
private String message;//原始异常信息,给程序员看,记录日志
private String info;//自定义信息,给用户看
public MyException(){
super();
}
public MyException(Date time,String msg,String info){
super();
this.time=time;
this.message=msg;
this.info=info;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
好的,有了这个自定义异常类,我们的指令类可以修改为:
package command;
import java.util.Date;
import entity.User;
import exception.MyException;
public class LoginCommand {//从此处向数据库类下操作指令
public User checkLogin(String userName,String userPassword) throws MyException{
if(userName.equals("")||userPassword.equals("")){
//抛出输入信息异常
throw new MyException(new Date(),"用户名或者密码为空","用户名或者密码为空");
}
User user=null;
try{
//从数据库中执行查询
}catch(Exception e){
throw new MyException(new Date(),e.getMessage(),"数据库访问异常");
}
return user;
}
}
task:1-5
,好的,此时,我们就可以在Servlet中调用LoginCommand 完成数据库操作了,代码如下:
package servlet;
import java.io.*;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import command.LoginCommand;
import entity.User;
import exception.MyException;
public class LoginServlet extends HttpServlet {//用于处理登录请求的LoginServlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);//直接调用doPost方法处理get请求
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {//处理post请求
//设置输入输出格式、编码
response.setContentType("text/html");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
//获取用户在网页输入的用户名和密码
String userName=request.getParameter("userName");
String userPassword=request.getParameter("userPassword");
//数据库操作
LoginCommand lc=new LoginCommand();
User user=null;
try {
user=lc.checkLogin(userName, userPassword);
if(user==null)
throw new MyException(new Date(),"用户名或者密码错误","用户名或者密码错误");
//根据user.getUserRole();用户角色显示不同内容
} catch (Exception e) {
//跳转到错误提示页面,并提示用户错误信息
}
}
}
task:1-6
,根据用户不同角色显示不同内容,是一个比较复杂的事情,这个猫哥下一篇博客再论,我们来先来实现比较简单的跳转到错误提示页面,并提示用户错误信息
。
修改LoginServlet 为:
package servlet;
import java.io.*;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import command.LoginCommand;
import entity.User;
import exception.MyException;
public class LoginServlet extends HttpServlet {//用于处理登录请求的LoginServlet
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);//直接调用doPost方法处理get请求
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {//处理post请求
//设置输入输出格式、编码
response.setContentType("text/html");
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
//获取用户在网页输入的用户名和密码
String userName=request.getParameter("userName");
String userPassword=request.getParameter("userPassword");
//数据库操作
LoginCommand lc=new LoginCommand();
User user=null;
try {
user=lc.checkLogin(userName, userPassword);
if(user==null)
throw new MyException(new Date(),"用户名或者密码错误","用户名或者密码错误");
//根据user.getUserRole();用户角色显示不同内容
} catch (MyException e) {
//跳转到错误提示页面,并提示用户错误信息
request.setAttribute("errorInfo", e.getInfo());//设置错误信息
request.getRequestDispatcher("/error.jsp").forward(request,response);//跳转到error.jsp
}
}
}
好的,最后,设计error.jsp为:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>error.jsp</title>
</head>
<body>
错误信息:${errorInfo}<br/>
<a href="login.jsp">点此返回登录页</a>
</body>
</html>
重新部署、运行后,测试输入空的内容,提交后发现:错误信息:用户名或者密码为空
,如果随便输如用户名密码,提交后发现:错误信息:用户名或者密码错误
。
最后,还有个问题,错误信息:用户名或者密码为空
,这个也太生硬了把,最好改为友情提示:用户名或者密码不能为空
。但是猫哥就是不改了,网站要个性!