欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Web开发分层思想

程序员文章站 2024-02-26 19:23:34
...

MVC开发模式:
M:Model模型       JavaBean&四种作用域
V:View视图            JSP
C:Controller控制器        Servlet

不使用框架,使用JSP+JavaBean+Servlet进行开发
Web开发分层思想
但是在实际开发中,我们进行更为细致的划分:
分层思想:强内聚,弱耦合
Web开发分层思想
整个业务流程是这样的:
浏览器即用户向服务器端发起请求,服务器端的控制器Servlet接收到用户的请求,做三件事:
1.获取表单的数据2.调用业务层的业务逻辑3.分发转向,其中调用的业务逻辑,业务层会去调用DAO层的基本增删改查方法,每一层都可以对JavaBean|三个域对象进行操作。最终结果通过JSP,返回给用户浏览器显示。
对于每一层,我们通常会创建如下包:
domain:JavaBean,实体bean,用于封装数据
service:业务层接口,如注册,登录……
service.impl:业务层接口的实现类
dao:dao接口,基本的增删改查方法
dao.impl:dao接口的实现类
servlet:servlet类
utils:工具类
exception:自定义异常类
jsp
其中接口可以看作是功能说明书,其中囊括了所有的方法。
下面写一个用户登录注册的Web小程序
Web开发分层思想
根据上述的分层思想,JavaWeb程序的架构如上图所示。
User:实体Bean,封装数据,其中字段的名称需与数据库字段保持一致
Web开发分层思想
Dao:数据访问层接口
Web开发分层思想
其中的方法都是基本的增删改查,可访问数据库中的数据
Dao.impl:Dao接口的实现类

package com.itdream.dao.impl;

import com.itdream.dao.UserDao;
import com.itdream.domain.User;
import com.itdream.exception.UserExcisException;
//自己写的操作数据库的工具类,具体实现方法见之前写的博文《JDBC技术》
import com.itdream.utils.DBUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;

/**
 * Created by Dream on 2017/12/1.
 */
public class UserDaoImpl implements UserDao {
    public void insert(User user)throws Exception{
        Connection con = null;
        PreparedStatement ps = null;

        try{
            con = DBUtils.getConnection();
            String sql = "insert into users (username,password,email,birthday) values(?,?,?,?)";
            ps = con.prepareStatement(sql);
            ps.setString(1,user.getUsername());
            ps.setString(2,user.getPassword());
            ps.setString(3,user.getEmail());
            SimpleDateFormat spf = new SimpleDateFormat("yyyy-MM-dd");
            String date = spf.format(user.getBirthday());
            ps.setString(4,date);

            int result = ps.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("插入失败!");
        }finally {
            DBUtils.closeAll(null,ps,con);
        }
    }
    public User select(User user)throws Exception{
        Connection con = null;
        ResultSet rs = null;
        PreparedStatement ps = null;
        User u = null;
        try{
            con = DBUtils.getConnection();
            String sql = "select * from users where username = ? and password = ?";
            ps = con.prepareStatement(sql);
            ps.setString(1,user.getUsername());
            ps.setString(2,user.getPassword());
            rs = ps.executeQuery();
            if(rs.next()){
                u = new User();
                u.setId(rs.getInt(1));
                u.setUsername(rs.getString(2));
                u.setPassword(rs.getString(3));
                u.setEmail(rs.getString(4));
                u.setBirthday(rs.getDate(5));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return u;
    }
    public boolean selectByName(String name){
        Connection con = null;
        ResultSet rs = null;
        PreparedStatement ps = null;
        try{
            con = DBUtils.getConnection();
            String sql = "select * from users where username = ?";
            ps = con.prepareStatement(sql);
            ps.setString(1,name);
            rs = ps.executeQuery();
            if(rs.next()){
                return true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }
}

service:业务层
Web开发分层思想
service.impl:业务层的实现类

package com.itdream.service.impl;

import com.itdream.dao.UserDao;
import com.itdream.dao.impl.UserDaoImpl;
import com.itdream.domain.User;
import com.itdream.exception.UserExcisException;
import com.itdream.service.UserService;

/**
 * Created by Dream on 2017/12/1.
 */
public class UserServiceImpl implements UserService {
    //通过调用Dao接口实现类的方法去操纵底层数据库
    UserDao userDao = new UserDaoImpl();
    public void register(User user)throws Exception{
        //注册也就是用户的插入
        userDao.insert(user);
    }
    public User login(User user){
        User u = null;
        try{
            //登录也就是用户的查找
            u = userDao.select(user);
        }catch (Exception e){
            e.printStackTrace();
        }
        return u;
    }
    public boolean findUserByName(String name)throws UserExcisException{
        boolean b = userDao.selectByName(name);
        //用户已经存在,需要抛出异常
        if(b){
            throw new UserExcisException("用户已经存在!");
        }
        return b;
    }
}

servlet:控制器Servlet类

登录:

public class LogServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException,ServletException{
        request.setCharacterEncoding("utf-8");
        //获取表单数据
        User user = new User();
        try{
            BeanUtils.populate(user,request.getParameterMap());
            //调用业务逻辑
            UserService us = new UserServiceImpl();
            User u = us.login(user);
            //如果u不为空,说明登录成功
            if(u != null){
                request.getSession().setAttribute("u",user);
                request.getRequestDispatcher("/index.jsp").forward(request,response);
            }else {  //否则登录失败,重新登录
                response.sendRedirect(request.getContextPath()+"/log.jsp");
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
        doGet(request,response);
    }
}

注册:
我们增加了用户表单注册信息的验证功能,增加了一个实体对象UserForm用于封装用户注册提交的表单数据,其中该对象的valid方法实现对用户注册信息的校验
UserForm类作为实体对象,我们也是放在domain包下,具体实现如下:

package com.itdream.domain;

import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Dream on 2017/12/2.
 */
public class UserForm {
    private int id;
    private String  username;
    private String password;
    private String repassword;
    private String email;
    private String birthday;

    Map<String,String> msg = new HashMap<>();
    //如果返回的msg不为空,证明是有错误消息的;否则,注册验证通过
    public boolean valid(){
        if("".equals(username)){
            msg.put("username","用户名不能为空!");
        }else if(!username.matches("\\w{3,8}")){
            msg.put("username","用户名必须为3~8位字母组成!");
        }

        if("".equals(password)){
            msg.put("password","密码不能为空!");
        }else if(!password.matches("\\d{3,8}")){
            msg.put("password","密码必须为3~8位数字!");
        }

        if(!password.equals(repassword)){
            msg.put("repassword","两次密码必须输入一致!");
        }

        if("".equals(email)){
            msg.put("email","邮箱不能为空!");
        }else if(!email.matches("^[a-z0-9]+([._\\\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$")){
            msg.put("email","必须要符合邮箱的格式输入");
        }

        if("".equals(birthday)){
            msg.put("birthday","生日不能为空!");
        }else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            try{
                sdf.parse(birthday);
            }catch (Exception e){
                msg.put("birthday","生日格式不对!");
            }
        }
        return msg.isEmpty();
    }

    //省略实例域的get,set方法

所以在注册实现的时候,需要加入表单验证操作:

public class RegServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException,ServletException{
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=utf-8");
        //获取表单数据
        User user = new User();
        UserForm uf = new UserForm();
        try{ // 将用户提交的注册信息注入到UserForm类中,首先进行校验,如果校验失败,则请求转发,同时将uf传递
            BeanUtils.populate(uf,request.getParameterMap());
            if(!uf.valid()){  //msg不为空,有错误
                request.setAttribute("uf",uf);
                request.getRequestDispatcher("/reg.jsp").forward(request,response);
                return;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        //如果执行到这里,说明校验成功,则将数据注入到User类中
        UserService us = new UserServiceImpl();
       try{
           /**使用BeanUtils实现对象数据自动set,但是时间设置会出现问题
           org.apache.commons.beanutils.converters.DateTimeConverter.toDate
           DateConverter does not support default String to 'Date' conversion.**/
           ConvertUtils.register(new DateLocaleConverter(), Date.class);
           BeanUtils.populate(user,request.getParameterMap());
           //调用业务逻辑
           //注册的用户如果存在,抛出异常UserExcisException
           boolean b = us.findUserByName(user.getUsername());
           us.register(user);
       }catch (UserExcisException e){
            request.setAttribute("error",e.getMessage());
            request.getRequestDispatcher("/reg.jsp").forward(request,response);
        }catch (Exception e){
           e.printStackTrace();
        }
        //分发转向
        response.getWriter().write("注册成功!1s后跳到主页...");
        response.setHeader("refresh","1;url="+request.getContextPath()+"/index.jsp");
    }
    public void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
        doGet(request,response);
    }
}

注销:这个很简单,只需要将session销毁即可

public class LogOutServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)throws IOException,ServletException{
        request.getSession().invalidate(); //session销毁
        response.sendRedirect(request.getContextPath()+"/index.jsp");
    }
    public void doPost(HttpServletRequest request,HttpServletResponse response)throws IOException,ServletException{
        doGet(request,response);
    }
}

JSP:
index.jsp:登录的时候将用户信息以变量u保存在session对象中,所以根据u是否为空来判断用户是否登录
Web开发分层思想
log.jsp:
Web开发分层思想
reg.jsp:注册时候,如果用户已经存在,则将该错误信息保存在request域对象的error变量里,校验信息放在uf变量里
Web开发分层思想



一些补充:
ConvertUtils.register注册转换器:当用到BeanUtils的populate方法(该方法可以实现用户提交的表单数据自动注入到实体对象中,动态获取,不需要我们通过set进行设置),其实都会调用convert进行转换,但Converter只支持一些基本的类型,甚至连java.util.Date类型也不支持。而且它比较笨的一个地方是当遇到不认识的类型时,居然会抛出异常来。
这个时候就需要给类型注册转换器。比如:意思是所以需要转成Date类型的数据都要通过DateLocaleConverter这个转换器的处理。
ConvertUtils.register(new DateLocaleConverter(), Date.class);