写了一个简单的实习生管理系统,用于自己复习java后端。由于是复习java为目的,故而这个系统没有用框架,control层基本手写servlet完成。基本的增删改查,级联删除功能均有实现。适合java刚入门的同学阅读,大神们请别见笑,如有错误欢迎指出。
一、系统简介:
1、MVC三层架构
2、control层手写servlet实现(封装BaseServlet)
3、MySQL数据库
4、前端框架miniui
二、系统功能简介:
1、有人员信息和考核信息两个界面
2、两个页面均能实现对应信息的增删改查,并且当删除某个人的信息时,自动删除这个人所有的考核信息。
3、人员的学号根据日期自动生成
4、新增信息对应的表单校验
前端是由框架实现,我写改项目时又以复习java为目的,故文中不会花篇幅介绍前端页面,感兴趣的同学可以去miniui官网查看其api文档。本文主要记录后端的实现即思路。
MVC三层架构,老生常谈的问题了。视图层View,与用户的交互及各个表单传参;模型层Model,模型负责各个功能的实现(如登录、增加、删除功能)。模型用JavaBean实现;控制层Controller,控制层负责将视图与模型一一对应起来。相当于一个模型分发器。
三、项目源码及大致实现思路:
1、BaseServlet
手动封装BaseServlet的目的是为了实现,在前端Ajax请求数据时能通过配置的web.xml和方法名请求到对应的control层方法,如:
$.ajax({
url : "trainee.do?method=saveTrainee",
type : 'post',
data : {
data : json
},
cache : false,
success : function(text) {
CloseWindow("save");
},
error : function(jqXHR, textStatus, errorThrown) {
alert(jqXHR.responseText);
CloseWindow();
}
});
通过封装BaseServlet和配置web.xml后,该Ajax请求将会从TraineeInfoServlet中的saveTrainee方法中请求数据。
BaseServlet的代码如下:
package com.epoint.action;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class BaseServlet extends HttpServlet {
//通用的servlet方法
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//对于以后的所有方法同一的做请求响应乱码处理
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//获取用户请求的方法
String methodName = request.getParameter("method");
//判断方法名是否为空 "" null
if (methodName.trim().isEmpty() || methodName == null) {
throw new RuntimeException("你没有传递method参数!无法确定你要调用的方法!");
}
//1. 获取当前类的class对象
Class c = this.getClass();
//2. 通过当前类的class对象的getMethod()方法查找是否存在对应方法
Method method = null;
try {
method = c.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
}
catch (Exception e) {
throw new RuntimeException("你要调用的方法!" + methodName + "不存在!");
}
//3. 通过反射动态的调用对应的方法
try {
//获取方法的返回值
String result = (String) method.invoke(this, request, response);
//判断是否有返回值 没有就什么都不做
if (result == null || result.trim().isEmpty()) {
return;
}
//查看返回值是否包含冒号,如果么有给用户抛异常
//如果有,使用冒号进行分割 前半[转发或重定向的标识]与后半[跳转的地址]
//做转发和重定向了
if (result.contains(":")) {
//拆分
//获取冒号的位置
int index = result.indexOf(":");
//获取冒号之前的
String s = result.substring(0, index);
//获取冒号之后的
String path = result.substring(index + 1);
if (s.equalsIgnoreCase("c")) {
//重定向
response.sendRedirect(request.getContextPath() + path);
}
else if (s.equalsIgnoreCase("z")) {
//转发
request.getRequestDispatcher(path).forward(request, response);
}
else {
throw new RuntimeException("你指定的操作" + s + "当前版本不支持!");
}
}
else {
//没有冒号
throw new RuntimeException("你指定跳转的URL存在问题!");
}
}
catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("你要调用的方法!" + methodName + "内部存在问题!");
}
}
}
2、JDBCUtils
连接数据库的工具类,代码如下:
package com.epoint.utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils {
// 配置文件的默认配置,必须给出c3p0-config.xml
private static ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 它是事务专用连接
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
/**
* 使用连接池返回一个连接对象
* @return
* @throws SQLException
*/
public static Connection getConnection() throws SQLException {
Connection con = tl.get();
// 当con不等于null,说明已经调用过beginTransaction(),表示开启了事务!
if (con != null)
return con;
return dataSource.getConnection();
}
/**
* 返回连接池对象!
* @return
*/
public static DataSource getDataSource() {
return dataSource;
}
/**
* 开启事务
* 1. 获取一个Connection,设置它的setAutoComnmit(false)
* 2. 还要保证dao中使用的连接是我们刚刚创建的!
* ----------------
* 1. 创建一个Connection,设置为手动提交
* 2. 把这个Connection给dao用!
* 3. 还要让commitTransaction或rollbackTransaction可以获取到!
* @throws SQLException
*/
public static void beginTransaction() throws SQLException {
Connection con = tl.get();
if (con != null)
throw new SQLException("已经开启了事务,请不要重复开启了!");
/*
* 1. 给con赋值!
* 2. 给con设置为手动提交!
*/
con = getConnection();//给con赋值,表示事务已经开始了
con.setAutoCommit(false);
tl.set(con);//把当前线程的连接保存起来!
}
/**
* 提交事务
* 1. 获取beginTransaction提供的Connection,然后调用commit方法
* @throws SQLException
*/
public static void commitTransaction() throws SQLException {
Connection con = tl.get();//获取当前线程的专用连接
if (con == null)
throw new SQLException("还没有开启事务,不能提交!");
/*
* 1. 直接使用con.commit()
*/
con.commit();
con.close();
// 把它设置为null,表示事务已经结束了!下次再去调用getConnection()返回的就不是con了
tl.remove();//从tl中移除连接
}
/**
* 提交事务
* 1. 获取beginTransaction提供的Connection,然后调用rollback方法
* @throws SQLException
*/
public static void rollbackTransaction() throws SQLException {
Connection con = tl.get();
if (con == null)
throw new SQLException("还没有开启事务,不能回滚!");
/*
* 1. 直接使用con.rollback()
*/
con.rollback();
con.close();
tl.remove();
}
/**
* 释放连接
* @param connection
* @throws SQLException
*/
public static void closeConnection(Connection conn) throws SQLException {
Connection con = tl.get();
/*
* 判断它是不是事务专用,如果是,就不关闭!
* 如果不是事务专用,那么就要关闭!
*/
// 如果con == null,说明现在没有事务,那么connection一定不是事务专用的!
if (con == null)
conn.close();
// 如果con != null,说明有事务,那么需要判断参数连接是否与con相等,若不等,说明参数连接不是事务专用连接
if (con != conn)
conn.close();
}
}
3、大致说明:
比较费脑筋的就这两个了,其余就是建立对应实体类,在action中的servlet中完成数据交互需要的方法,根据需求完成对应的sql语句,一些工具类的调用等等。不做过多详述,如有需要可以下载笔者项目源码,如有不对的地方,请大家指出。
4、项目分享:
网盘地址:https://pan.baidu.com/s/1YiIX52tvAsrM8knI4j0grw
提取码:7tdj