搭建MVC模型
大家应该都知道MVC(Model View Controller)模型,也就是模型(model)-视图(view)-控制器(controller)
他是最常见的软件架构之一,现在市面上很多模型都是基于MVC,百变不离其宗。
STEP1: View 传送指令到 Controller
STEP2: Controller 完成业务逻辑后,要求 Model 改变状态
STEP3: Model 将新的数据发送到 View,用户得到反馈
那么根据MVC模型,我们就可以建立相应的功能包了
这里我来解释以下,bean包主要存放的是JavaBean实体类,比如说User,Customer等
dao层和dao.impl则是直接和数据库打交道的包,因此里面就涉及到JDBC的一系列操作了。
service包和service.impl则是将数据库中查询出来的数据进行处理,比如说数据组装,异常处理等等,形成一个较为完善的功能,这两个包都隶属于Model。
servlet包顾名思义就是存储Servelt类的包了,Servlet也就是连接页面和后台之间的一座桥梁了,因此他存在的意义也非凡,它隶属于Controller层。
那么View层都有些什么呢?view就是给客户看的东西,大家应该可以想到了对吧~
我们的HTML网页就是给客户看的,但是一般使用jsp将页面的内容动态的渲染出来,将jsp和Servlet以及Model层和数据库成功搭建起来,我们的项目才算完成。这里我的项目主要是处理后台,main.jsp为我们的主页面,包含功能菜单,Login登陆验证项目具体可以查看Marco’s Java 之【JSON&AJAX&登陆验证小项目】
准备工作
其他功能包介绍
Ok,讲了这么多大家可能发现还有几个包不知道是做什么用的,anno,comm和util
anno(Annotation): 存放注解,这个主要是为了结合我写的一套BaseDao中的通用添加数据到数据库使用的,具体可以点击查看文章 Marco’s Java 之【JDBC辅助类封装】
comm(Comment): 存放辅助信息类,这个我们下面再讲
util: 存放工具类
下面是anno(Annotation)的代码,比较简单,一个Column和一个Table,对类和类属性进行注释
@Target(value=ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value() default "";
}
@Target(value=ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value() default "";
}
接下来是util,网上其实有很多工具类,大家也可以根据需求自行封装
/*用于检查元素是否为空,主要用于前后端数据是否为空的校验*/
public class CheckParamUtil {
public static boolean isBlank(Object element) {
return (element == null) || "".equals(element);
}
public static String checkEmpty(Map<String,String[]> params , String...keys) {
for (int i = 0; i < keys.length; i++) {
String key = keys[i];
String[] values = params.get(key);
if(!params.containsKey(key)) {
return CodeMsg.PARAM_INCOMPLETE.getMessage() + "【"+ key +"】";
}
String valueStr = Arrays.toString(values);
valueStr = valueStr.substring(1,valueStr.length()-1).trim();
if(valueStr == null || "".equals(valueStr)) {
return CodeMsg.PARAM_BLANK.getMessage() + "【"+ key +"】";
}
}
return null;
}
}
/*模拟数据库连接池,一般来说小项目其实不需要连接池,但是也是为了模拟使用嘛*/
public class ConnPool {
private static String driver = null;
private static String url = null;
private static String userName = null;
private static String password = null;
private final static int MINSIZE = 5;//最小连接数量为5
private final static int MAXSIZE = 10;//最大连接数量为10
private static Properties pro = new Properties();
//创建一个线程池,用于存储本地的Connection
private LinkedList<Connection> connPool = new LinkedList<Connection>();
//记录当前的连接数量
private int currentSize = 0;
//获取操作对象
public static void main(String[] args) {
ConnPool cp = new ConnPool();
System.out.println(cp.getConnection());
System.out.println(cp.getConnection());
System.out.println(cp.getConnection());
}
//加载驱动
static {
try {
pro.load(ConnPool.class.getClassLoader().getResourceAsStream("config.properties"));
driver = pro.getProperty("driver");
url = pro.getProperty("url");
userName = pro.getProperty("username");
password = pro.getProperty("password");
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public ConnPool() {
for (int i = 0; i < MINSIZE; i++) {
Connection conn = this.createConn();
connPool.add(conn);
currentSize ++;
}
}
//获取连接对象(内部使用)
private Connection createConn() {
Connection conn = null;
//如果当前线程中没有绑定相应的Connection
try {
conn = DriverManager.getConnection(url, userName, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public Connection getConnection() {
if(connPool.size() > 0) {
Connection conn = connPool.getFirst();
connPool.removeFirst();
return conn;
} else if(connPool.size()==0 && currentSize< MAXSIZE) {
currentSize++;
connPool.addLast(this.getConnection());
Connection conn = connPool.getFirst();
connPool.removeFirst();
return conn;
}
throw new RuntimeException("连接数量已经到到达上限,请稍等");
}
public void realse(Connection conn) {
//ThreadLocal取得当前线程的connection
connPool.add(conn);
}
//让当前线程放行
public static void realse(PreparedStatement ps) {
if(ps != null) {
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void realse(ResultSet rs, PreparedStatement ps) {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
realse(ps);
}
}
/*时间工具类,这个工具类的作用有很多,比如说前后端的时间的格式转化,或者生成不重复的数据串*/
public class DateUtil {
public final static String yyyyMMddHHmmssSSS = "yyyyMMddHHmmssSSS";
public final static String yyyyMMdd = "yyyy-MM-dd";
public static String getDateString(String fomart) {
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(fomart);
return simpleDateFormat.format(date);
}
public static Date StingToDate(String Date, String dateFormat) {
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
Date date = null;
try {
date = sdf.parse(Date);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
public static String getDateString(Date date, String fomart) {
SimpleDateFormat sdf = new SimpleDateFormat(fomart);
return sdf.format(date);
}
public static Date addDate(Date date, int num) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DATE, num);
return calendar.getTime();
}
}
/*这个工具主要是将获取前台的数据的操作简化,并排除非空*/
public class ServletUtil {
/**
* 获取页面的上的参数和值,将其封装到Map集合中
* @param request
* @param params
* @return Map
*/
public static Map<String, Object> putInMap(HttpServletRequest request, String...params) {
Map<String, Object> paramMap = new HashMap<String, Object>();
for (int i = 0; i < params.length; i++) {
String paramName = params[i];
String paramValue = request.getParameter(paramName);
if(!CheckParamUtil.isBlank(paramValue)) {
paramMap.put(paramName, request.getParameter(paramName));
}
}
return paramMap;
}
/*简化前台信息打印操作*/
public static void print(Result result, HttpServletResponse response) {
try {
response.getWriter().print(result.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
}
上面的包中的类也比较简单,接下来还有一个包没有讲,就是comm包,这个包中我存放了三个类
准确来说是两个普通类(PageQueryInfo,Result,CodeMsg),一个枚举类
CodeMsg主要是将成功的信息和他的code(这个可以自己随意取,后期可以做成API供阅览)封装起来,便于前台jsp获取解析后台的结果
public enum CodeMsg {
SUCCESS("200","SUCCESS"),
LOGIN_ERROR("10001","USERNAME OR PASSWORD INCORRECT"),
PARAM_ERROR("10002","PARAM ECC ERROR "),
PARAM_BLANK("100021","PARAM CAN'T BE BLANK"),
PARAM_INCOMPLETE("100022","PARAM IS INCOMPLETE"),
CHECK_CODE_ERROR("10003","CHECK CODE INCORRECT"),
DELETE_DATA_FAILED("10004","DELETE FAILED"),
ADD_DATA_FAILED("10005","ADD FAILED"),
FILE_UPLOAD_ERROR("20001","FILE UPLOAD FAILED"),
FILE_UPLOAD_SUCCESS("0","FILE UPLOAD SUCCESS"),
DATA_NOT_FOUNT("404","DATA NOT FOUND"),
AVATAR_UPDATE_ERROR("20002","FILE UPDATE FAILED"),
EDIT_DATA_ERROR("30001","DATA WERE EDIT FAILED"),
BATCH_UPDATE_ERROR("50001","BATCH UPDATE FAILED"),
VISITLOG_UPDATE_ERROR("20002","VISITLOG UPLOAD FAILED"),
ATHORIZE_ROLE_FAILED("60001","ATHORIZE ROLE FAILED");
private final String code;
private final String message;
private CodeMsg(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() {
return code;
}
public String getMessage() {
return message;
}
}
PageQueryInfo主要是辅助分页查询,封装了分页查询的一些必备项,比如说查询到的数据一共多少个,每一页有多长,一共多少页
public class PageQueryInfo {
private int count;//查询到的数据总数
private int limit;//单页行数
private int totalPage;//总页数
/**
* 查询到的数据
*/
private Object data;
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
Result则是在CodeMsg枚举的基础上再封装
public class Result {
/**
* 业务编码
*/
private String code;
/**
* 业务消息
*/
private String message;
/**
* 返回的数据
*/
private Object data;
public Result(CodeMsg codeMsg) {
super();
this.code = codeMsg.getCode();
this.message = codeMsg.getMessage();
}
public Result(CodeMsg codeMsg, Object data) {
super();
this.code = codeMsg.getCode();
this.message = codeMsg.getMessage();
this.data = data;
}
public Result(CodeMsg codeMsg, String errorMsg) {
super();
this.code = codeMsg.getCode();
this.message = errorMsg;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
/**
* 重写toString方法,将对象以JSON字符串的形式输出并传递
*/
@Override
public String toString() {
return JSONObject.toJSONString(this);
}
/**
* 根据返回的code判断是否登录成功
* @return
*/
public boolean isSuccess() {
return "200".equals(this.code);
}
}
接下来就是导包了,切记我们在做Servlet项目的所有jar包要放在WEB-INF文件夹下的lib子文件夹中而不再是在Java文件的根目录下,因为我们的程序,或者说我们的工作空间是在tomcat的webapps文件夹中。
由于前端是layui框架完成的,所以我这里增加了layui的文件夹,大家可以在layui官网上下载最新版本