MVC模式
MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式
-Model(模型)。是应用程序中用于处理应用程序数据逻辑的部分。
-View(视图)。是应用程序中处理数据显示的部分。
-Controller(控制器)是应用程序中处理用户交互的部分。
例如:
我们在View输入账号密码,点击登陆,然后触发Controller调用Model的方法
Model检查后发现错误,返回出错信息,Controller再把错误信息显示在View上。
用户修改正确以后,Controller再调用登陆方法进行登陆。
下面两张逻辑图帮我们理清思路
Java Web的三层架构
-表示层(web层):包含JSP,Servlet等web相关的内容
-业务逻辑层(Service):处理业务,
-数据层(DAO Data Access Object):也叫持久层,封装了对数据库的访问细节,一般写DAO类
我们写项目时一般要分成这三层。
-Web层,Servlet,jsp等。
-Service层(业务逻辑层)
-Dao层(数据层)
案例:使用三层架构完成注册登录的功能
项目分析
1)先创建空项目
2)创建包和类
-domain包:创建User类,是一个javabean
-web包:用来存放登录注册的servlet,与web相关的类
-service包:用来处理业务逻辑
-dao包:用来负责处理用户数据
3)代码的实现
我们一般是jsp页面将表单数据传入servlet
servlet依赖service层来处理具体业务逻辑
service层依赖dao层来进行数据的处理
注册流程
1)首先创建register.jsp页面完成注册页面,也就是表单,我们只需要添加账号密码验证码这三项即可。
2)表单中的数据提交给RegisterServlet,把数据封装到User对象中,RegisterServlet需要完成表单的检测,例如账号长度等。
3)具体的实现应该交给业务逻辑层来实现,所以RegisterServlet中应该调用UserService的register方法,并将user对象传入。
4)UserService的register方法,应该完成用来检测用户名是否被注册
-如果已经注册,则抛出异常,这个异常是我们的自定义异常,因为我们要自定义异常信息
-没有注册,就进行注册,当然需要调用数据层
5)数据层应该实现两个方法
-通过用户名查找对象
-添加用户
我们还没有学数据库,所以在xml文件中存取数据
登录流程
1)创建login.jsp完成登陆页面
2)登陆页面中的表单提交给LoginServlet
3)LoginServlet将对象封装,调用service的login方法来处理具体的业务逻辑
4)UserService的login方法
-检测有没有该用户,没有的话就抛出异常
-有的话,检测密码是否正确,不正确就抛出异常,正确就返回user对象
//我们首先创建cn.xxx.domain包,在domain包里创建一个javabean User类,用来封装对象
public class User {
private String username; //用户名
private String password; //密码
private String vcode; //验证码
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getVcode() {
return vcode;
}
public void setVcode(String vcode) {
this.vcode = vcode;
}
public String toString() {
return "User [username=" + username + ", password=" + password + ", vcode=" + vcode + "]";
}
}
然后创建cn.xxx.dao包,创建数据层的类UserDao,类里应该实现两个方法
-通过用户名查找对象方法
-添加用户方法
package cn.cad.dao;
import java.io.FileOutputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import cn.cad.domain.User;
public class UserDao {
private String path="E://users.xml"; //我们还没有学数据库,所以在xml文件中存放数据
public User findByUsername(String username) //通过用户名查找对象的方法
{
try{
SAXReader saxReader=new SAXReader(); //通过dom4j和xpath查找对象
4
Document document=saxReader.read(path);
Element e=(Element) document.selectSingleNode("//user[@username='"+username+"']");
if(e!=null)
//如果对象不为空,则将属性值username和password封装成user对象返回,否则返回空,就是没找到该用户
{
String name=e.attributeValue("username");
String passwd=e.attributeValue("password");
User user=new User();
user.setUsername(name);
user.setPassword(passwd);
return user;
}
return null;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public void addUser(User user) //添加用户的方法
{
//将传进来的user对象添加到xml文件中
try{
SAXReader saxReader=new SAXReader();
Document document=saxReader.read(path);
Element root=document.getRootElement();
Element newuser=root.addElement("user");
newuser.addAttribute("username", user.getUsername());
newuser.addAttribute("password", user.getPassword());
OutputFormat format=OutputFormat.createPrettyPrint();
XMLWriter xmlWriter=new XMLWriter(new FileOutputStream(path),format);
xmlWriter.write(document);
xmlWriter.close();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
}
我们需要自定义异常,因为当我们出现各种错误时时我们需要来抛出异常。所以我们需要来自定义一个异常类。
我们只需要继承Exception类,然后就不用管其他的。我们把这个类放在cn.xxx.service包里。
package cn.cad.service;
public class UserException extends Exception{
public UserException() {
super();
// TODO Auto-generated constructor stub
}
public UserpException(String arg0, Throwable arg1, boolean arg2, boolean arg3) {
super(arg0, arg1, arg2, arg3);
// TODO Auto-generated constructor stub
}
public UserException(String arg0, Throwable arg1) {
super(arg0, arg1);
// TODO Auto-generated constructor stub
}
public UserException(String arg0) {
super(arg0);
// TODO Auto-generated constructor stub
}
public UserException(Throwable arg0) {
super(arg0);
// TODO Auto-generated constructor stub
}
}
cn.xxx.service包。我们创建UserService类用来处理业务逻辑,需要实现两个业务逻辑的处理
-注册
-登陆
package cn.cad.service;
import cn.cad.dao.UserDao;
import cn.cad.domain.User;
public class UserService {
private UserDao userdao=new UserDao(); //依赖数据层
public void register(User user) throws UserException //注册业务逻辑的处理方法
{
//表单中的数据被封装成user对象传入servlet,然后servlet再把对象传进来,让service实现具体的业务逻辑处理,我们先查找用户是否存在,存在就抛出用户名已存在的异常,不存在就调用添加用户的方法
User _user=userdao.findByUsername(user.getUsername());
if(_user!=null)
{
throw new UserException("用户名"+user.getUsername()+"已存在");
}
userdao.addUser(user);
}
//处理登陆的业务逻辑的方法。先查找用户是否存在,不存在就抛出用户未找到异常。
//存在再判断密码是否正确,不正确抛出密码错误异常,正确就返回该对象。
public User login(User user) throws UserException {
User _user=userdao.findByUsername(user.getUsername());
if(_user==null)
{
throw new UserException("用户未找到");
}
if(!user.getPassword().equals(_user.getPassword()))
{
throw new UserException("密码错误");
}
return _user;
}
}
//创建cn.xxx.web.servlet包,来处理web层。
//RegisterServlet来进行表单检测和调用service的register方法。
package cn.cad.web.servlet;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.cad.domain.User;
import cn.cad.service.UserException;
import cn.cad.service.UserService;
public class RegiserServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8"); //设置编码
response.setContentType("text/html;charset=utf-8");
String name=(String) request.getParameter("username"); //获取表单数据
String passwd=(String) request.getParameter("password");
String vcode=request.getParameter("vcode");
//进行表单检测,map集合用来存放错误信息,因为可能有很多错误信息,我们使用键值对来存放
Map <String,String>errmsg=new HashMap<String,String>();
//判断用户名的长度和是否为空
if(name==null||name.trim().isEmpty())
{
errmsg.put("username", "用户名不能为空");
}else if(name.length()<=3||name.length()>=15)
{
errmsg.put("username", "用户名必须在3到15位之间");
}
//判断密码的长度和是否为空
if(passwd==null||passwd.trim().isEmpty())
{
errmsg.put("password", "密码不能为空");
}else if(passwd.length()<=3||passwd.length()>=15)
{
errmsg.put("password", "密码必须在3到15位之间");
}
//判断验证码的长度,是否为空和是否正确
if(vcode==null||vcode.trim().isEmpty())
{
errmsg.put("vcode", "验证码不能为空");
}else if(vcode.length()!=4)
{
errmsg.put("vcode", "验证码长度错误");
}else if(!vcode.equalsIgnoreCase((String) request.getSession().getAttribute("text")))
{
errmsg.put("vcode", "验证码错误");
}
//判断map集合长度,如果大于0,说明有错误信息,保存到request欲,将用户的信息也保存起来,用来回显
if(errmsg.size()>0)
{
request.setAttribute("errmsg", errmsg);
request.setAttribute("name", name);
request.setAttribute("passwd", passwd);
request.setAttribute("vcode", vcode);
request.getRequestDispatcher("/user/register.jsp").forward(request, response);
return;
}
//封装user对象,调用service的register方法,如果什么都没有,则显示注册成功,不成功就捕获异常信息保存到request域,转发到注册页面
User user=new User();
user.setUsername(name);
user.setPassword(passwd);
UserService userservice=new UserService();
try {
userservice.register(user);
response.getWriter().print("注册成功<a href='"+request.getContextPath()+"/user/login.jsp'>点击跳转</a>");
} catch (UserException e) {
// TODO Auto-generated catch block
String msg=e.getMessage();
request.setAttribute("msg", msg);
request.getRequestDispatcher("/user/register.jsp").forward(request, response);
}
}
}
LoginServlet用来处理登陆
package cn.cad.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.cad.domain.User;
import cn.cad.service.UserService;
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8"); //设置编码
response.setContentType("text/html;charset=utf-8");
//将登录的表单信息封装成对象,然后调用业务逻辑层的login方法
如果成功,则将返回来的user对象保存在session域中,不成功则将异常信息保存在request域中,转发到登陆页面
String name=request.getParameter("username");
String passwd=request.getParameter("password");
User user=new User();
user.setUsername(name);
user.setPassword(passwd);
UserService userservice=new UserService();
try {
User sessionuser=userservice.login(user);
request.getSession().setAttribute("sessionuser", sessionuser);
response.sendRedirect("/User/user/welcome.jsp");
} catch (Exception e) {
request.setAttribute("msg", e.getMessage());
request.getRequestDispatcher("/user/login.jsp").forward(request, response);
}
}
}
生成验证码的servlet,需要用到我们以前编写过的一个验证码生成类。
package cn.cad.web.servlet;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class VerifiCodeServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
VerifiCode v=new VerifiCode(); //创建验证码生成类
BufferedImage bi=v.getImage(); //获取验证码图片
request.getSession().setAttribute("text", v.getText()); //将验证码的正确字符串保存在session域中,以方便判断
v.output(bi, response.getOutputStream()); //将验证码写入到页面
}
}
登陆页面login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>登陆页面</h1>
<form action="/User/LoginServlet" method="post">
用户名:<input type="text" name="username"><br/>
密 码:<input type="password" name="password"><br/>
<input type="submit" value="登录"><br/>
<a href="/User/user/register.jsp">没有账号?点击注册</a>
<br/>
${msg } //用来显示错误信息
</form>
</body>
</html>
注册页面register.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
function change()
{
var img=document.getElementById("image");
img.src="/User/VerifiCodeServlet?a="+new Date().getTime();
}
</script>
</head>
<!--每一个input的后面都有一个用来显示错误信息的el表达式-->
<body>
<h1>注册页面</h1>
<form action="/User/RegiserServlet" method="post">
用户名:<input type="text" name="username" value="${requestScope.name }">${requestScope.errmsg.username }<br/>
密 码:<input type="password" name="password" value="${requestScope.passwd }">${requestScope.errmsg.password }<br/>
验证码:<input type="text" name="vcode" size="3" value="${requestScope.vcode }">
<img src="/User/VerifiCodeServlet" id="image">
<a href="javascript:change()">看不清,换一张</a>
${requestScope.errmsg.vcode }
<br/>
<input type="submit" value="注册">
</form>
${ requestScope.msg}
</body>
</html>
登陆成功页面welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<!--判断session域中是否有user对象,没有就不让看-->
<body>
<c:choose>
<c:when test="${empty sessionScope.sessionuser }">对不起,请您先登录</c:when>
<c:otherwise>欢迎登录本系统,${sessionScope.sessionuser }</c:otherwise>
</c:choose>
</body>
</html>