对于一些小项目模块时,很多时候我们使用繁琐的框架实在有些麻烦(导包多还可能版本不兼容,搭建麻烦),当离开框架后我们如何更好的撸代码呢?本文首先感谢我的老师龙sir的授业指导,文中部分代码和思想来源于我的老师,我只是结合自己的编程经验和实际开发对其进行了总结和修改整理,希望同大家分享,如果有不足之处望大家指出,希望大家能够共同学习和进步!
先上图,基于MVC模式的包结构:
然后聊聊增删改查,开始上Util包代码:
首先数据库配置文件的加载——JdbcUtil
1、(.properties文件的加载方式很多,大家可以上论坛搜索下)
2、单例模式此处建议使用饿汉式减少线程冲突,不建议以下模式,设计模式大家可以参考我上传的 “Java常用设计模式源码”
http://download.youkuaiyun.com/detail/zyp689/9828252
package com.zyp168.util;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/*
* 数据库访问JDBC工具类
*/
public class JdbcUtil {
// ---单例模式---
private static JdbcUtil jdbcUtil;
private static Properties properties = new Properties();
private static String jdbc_driver;
private static String jdbc_url;
private static String jdbc_user;
private static String jdbc_pwd;
//懒汉式-单例模式
private JdbcUtil() {
}
public static JdbcUtil getInstance() {
if (jdbcUtil == null) {
jdbcUtil = new JdbcUtil();
}
return jdbcUtil;
}
// ---静态代码块---
static {
InputStream inputStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("mysqlConfig.properties");
try {
properties.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
jdbc_driver = properties.getProperty("driver");
jdbc_url = properties.getProperty("url");
jdbc_user = properties.getProperty("user");
jdbc_pwd = properties.getProperty("pwd");
try {
Class.forName(jdbc_driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// ---获取连接---
public Connection getConnection() {
Connection connection = null;
try {
connection = DriverManager.getConnection(jdbc_url, jdbc_user, jdbc_pwd);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
// ---关闭资源---
public void close(Connection connection, Statement stmt, ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
注:单例模式
package com.zyp168.single;
/**
* 单例模式
*
* 饿汉式的优势在于能够有效解决线程并发问题; static修饰的变量会被作为GC的root根节点不能被回收;static
* 字段(类的成员变量)在类的所有实例中只存在一次;static会将被修饰者与类直接产生引用关系,而非与类的实例。
* final修饰的变量值不会改变可节省空间,修饰的类不能被继承。
*
*/
public class SingleTest {
public static void main(String[] args) {
// 由于private修饰并重写了构造方法,故不能使用new LSingle()创建对象
LSingle.getInstance();
ESingle.getInstance();
}
}
/*
* 懒汉式
*/
class LSingle {
private static LSingle lSingle = null;
private LSingle() {
//拒绝外部类new LSingle()方式创建对象
}
public static LSingle getInstance() {
if (lSingle == null) {
lSingle = new LSingle();
}
return lSingle;
}
}
/*
* 饿汉式
*/
class ESingle {
// 此处final是为了节省空间,可以不要
private static final ESingle eSingle = new ESingle();
private ESingle() {
//拒绝外部类new ESingle()方式创建对象
}
public static ESingle getInstance() {
return eSingle;
}
}
注:不同数据库的配置文件格式:(下面是mysql版、 oracle XE版、sqlserver2008 XE版)
其次CRUD模版——JdbcTemplate
package com.zyp168.util;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/*
* Jdbc的模板:提取出更新和查询方法封装
*/
public class JdbcTemplate {
// 单例模式:static修饰的字段可以直接建立引导关系(不需要使用new其类再调用,可以直接用类.方法的形式调用),且只会被创建一次,位于gc根目录不被回收,会造成内存泄露
private static JdbcTemplate jdbcTemplate;
private JdbcTemplate() {
// 默认构造方法
}
public static JdbcTemplate getInstance() {
if (jdbcTemplate == null) {
jdbcTemplate = new JdbcTemplate();
}
return jdbcTemplate;
}
// 封装更新操作(增、删、改)
public boolean update(String sql, Object[] objArr) {
// 初始化成员变量
boolean flag = false;
Connection con = null;
PreparedStatement pstmt = null;
// 注册并链接
con = JdbcUtil.getInstance().getConnection();
try {
// pstmt
pstmt = con.prepareStatement(sql);
if (objArr!=null) {
for (int i = 1; i <= objArr.length; i++) {
pstmt.setObject(i, objArr[i - 1]);
}
}
// 执行
int result = pstmt.executeUpdate();
// 受影响行数大于零返回ture
flag = (result > 0);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.getInstance().close(con, pstmt, null);
}
return flag;
}
// 封装单条查询操作
public Object findOneInfo(String sql, Object[] objArr, JdbcMapper mapper) {
// 初始化成员变量
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
Object rsObject = null;
// pstmt
try {
con = JdbcUtil.getInstance().getConnection();
pstmt = con.prepareStatement(sql);
if (objArr!=null) {
for (int i = 1; i <= objArr.length; i++) {
pstmt.setObject(i, objArr[i - 1]);
}
}
// 执行
rs = pstmt.executeQuery();
if (rs.next()) {
rsObject = mapper.mappinng(rs);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 查询
JdbcUtil.getInstance().close(con, pstmt, rs);
}
return rsObject;
}
// 封装查询多条操作
public List<? extends Object> findAllInfo(String sql, Object[] objArr,
JdbcMapper mapper) {
List<Object> list = new ArrayList<Object>();
// 初始化变量
Object rsObject = null;
// Connection.createStatement() 创建一个 Statement 对象来将 SQL 语句发送到数据库。
Connection con = null;
// PreparedStatement表示预编译的 SQL 语句的对象,Statement 对象的子接口
PreparedStatement pstmt = null;
// ResultSet查询获得的数据表,next方法将光标移动到下一行对象(对应数据库表中的行),没有下一行时返回 false;
ResultSet rs = null;
try {
// 注册并链接
con = JdbcUtil.getInstance().getConnection();
// 创建PreparedStatement对象
pstmt = con.prepareStatement(sql);
if (objArr!=null) {
for (int i = 1; i <= objArr.length; i++) {
pstmt.setObject(i, objArr[i - 1]);
}
}
// 执行
rs = pstmt.executeQuery();
while (rs.next()) {
rsObject = mapper.mappinng(rs);
list.add(rsObject);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtil.getInstance().close(con, pstmt, rs);
}
return list;
}
}
然后ORM映射文件——JdbcMapper (想下Hibernate或Mabatis中的xml映射文件是否感觉特别熟悉?

package com.zyp168.util;
import java.sql.ResultSet;
/*
* 对象映射接口
*/
public interface JdbcMapper {
public abstract Object mappinng(ResultSet rs);
}
实例:
package com.zyp168.model.mapper;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.zyp168.model.User;
import com.zyp168.util.JdbcMapper;
public class UserMapper implements JdbcMapper {
@Override
public Object mappinng(ResultSet rs) {
User user = new User();
try {
//ORM映射
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setPwd(rs.getString("pwd"));
} catch (SQLException e) {
// 实体类属性和数据库表中字段的映射关系不匹配
e.printStackTrace();
}
return user;
}
}
实例:原生的CRUD \ 第三方DbUtil包\ JdbcTemplate比较
package com.zyp168.dao.impl;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import com.zyp168.dao.UserDao;
import com.zyp168.model.User;
import com.zyp168.util.JdbcTemplate;
import com.zyp168.util.JdbcUtil;
import com.zyp168.util.PageModel;
public class UserDaoImpl implements UserDao {
/*
* 单例模式--饿汉式
*/
private final static UserDaoImpl userDaoImpl=new UserDaoImpl();
private UserDaoImpl() {
}
public static UserDao getInstance() {
return userDaoImpl;
}
@Override
public boolean register(User user) {
/**
* TODO 原生Jdbc实现更新操作
*/
boolean flag = false;
Connection connection = null;
PreparedStatement pstmt = null;
// 注册驱动,连接数据库
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "root", "root");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
// 编写Sql
String sql = "INSERT INTO user VALUES(NULL,?,?)";
// 预编译Sql
try {
pstmt = connection.prepareStatement(sql);
pstmt.setObject(1, user.getName());
pstmt.setObject(2, user.getPwd());
} catch (SQLException e) {
e.printStackTrace();
}
// 执行Sql并返回结果
try {
int result = pstmt.executeUpdate();// 受影响条数
flag = result > 0;
} catch (SQLException e) {
e.printStackTrace();
}
// 关闭资源
JdbcUtil.getInstance().close(connection, pstmt, null);
return flag;
}
@Override
public User login(User user) {
/**
* TODO 原生Jdbc实现查询操作
*/
User model = new User();
Statement stmt = null;
ResultSet rs = null;
Connection connection = JdbcUtil.getInstance().getConnection();
StringBuffer sbf = new StringBuffer();
sbf.append("SELECT * FROM user WHERE name='").append(user.getName())
.append("' AND pwd='").append(user.getPwd() + "'");
String sql = sbf.toString();
// 编译执行Sql并返回结果
try {
stmt = connection.createStatement();
// 返回的是第一行的各属性的Map键值对(键分类存储),其中next()方法将游标移动到下一行位置,如果下一行为空返回false
rs = stmt.executeQuery(sql);
if (rs.next()) {
model.setId(rs.getInt("id"));
model.setName(rs.getString("name"));
model.setPwd(rs.getString("pwd"));
}
} catch (SQLException e) {
e.printStackTrace();
}
JdbcUtil.getInstance().close(connection, stmt, rs);
return model;
}
@Override
public boolean repwd(User user) {
/**
* TODO 使用自定义封装的JdbcTemplate+JdbcMapper模板进行操作
*/
String sql = "UPDATE user SET pwd=? WHERE name=?";
Object[] objArr = { user.getPwd(), user.getName() };
return JdbcTemplate.getInstance().update(sql, objArr);
}
@Override
public List<User> findByCondition(Map<String, String> condition,
PageModel<User> page) {
/**
* TODO 使用第三方工具包DbUtils实现,API地址如下
* http://commons.apache.org/proper/commons-dbutils/apidocs/
*/
List<User> list = new ArrayList<User>();
Connection connection = JdbcUtil.getInstance().getConnection();
StringBuffer sb = new StringBuffer();
/* 查询条件集合 */
List<Object> objects = new ArrayList<Object>();
// 查询所有
if (condition == null) {
sb.append("SELECT * FROM user WHERE 1 = 1 ");
}
// 模糊查询
if (condition != null) {
if (condition.get("name") != null || condition.get("name") != "") {
sb.append(" AND name LIKE CONCAT('%',?,'%')");
objects.add(condition.get("name"));
}
}
// 分页查询
if (page != null) {
sb.append("LIMIT ?, ?");
objects.add((page.getPageNum() - 1) * page.getPageSize());
objects.add(page.getPageSize());
}
//
QueryRunner queryRunner = new QueryRunner();
try {
list = queryRunner.query(connection, sb.toString(),
new BeanListHandler<User>(User.class), objects);
} catch (SQLException e) {
e.printStackTrace();
}
DbUtils.closeQuietly(connection);
return list;
}
}
简单说说分页实例(不完整,按实际情况灵活处理)——PageModel、PageTag
package com.zyp168.util;
import java.io.Serializable;
import java.util.List;
/**
* 分页要求:根据页码获取该页的数据集合(注:每页数据行数大小已知)
* 分页实体类: pageNum 页码/当前页 pageSize 每页大小 pageCount 总页数 recordCount 总记录数 List<T> 分页查询获得的数据集合
* 主要方法:首页 上一页 下一页 尾页 查询所有获取总记录数 分页查询获取当前页码数据集合
*/
public class PageModel<T> implements Serializable {
// Java序列化
private static final long serialVersionUID = 1L;
// 分页相关参数
private Integer pageNum;
private Integer pageSize; //常量
private Integer recordCount; //BaseDaoImpl.findAll()查询
private Integer pageCount; //可根据上述三参数计算获得: 改写 PageModel<T>.getPageCount() 方法
private List<T> pageList; //BaseDaoImpl<T>.queryByPage(PageModel page)查询
// 自定义成员方法 :首页 上一页 下一页 尾页
/**
* 获取首野
* @return 1
*/
public Integer getFirstPage() {
return 1;
}
/**
* 获取上一页
* @return
*/
public Integer getPreviousPage() {
if (pageNum <= 1) {
return 1;
} else {
return pageNum - 1;
}
}
/**
* 获取下一页
* @return
*/
public Integer getNextPage() {
if (pageNum >= this.getPageCount()) {
return this.getPageCount();
} else {
return pageNum + 1;
}
}
/**
* 获取末页
* @return
*/
public Integer getLastPage() {
return this.getPageCount();
}
// 构造函数
public PageModel() {
super();
}
public PageModel(Integer pageNum, Integer pageSize, Integer recordCount,
Integer pageCount, List<T> pageList) {
super();
this.pageNum = pageNum;
this.pageSize = pageSize;
this.recordCount = recordCount;
this.pageCount = pageCount;
this.pageList = pageList;
}
// getter 和 setter方法
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getRecordCount() {
return recordCount;
}
public void setRecordCount(Integer recordCount) {
this.recordCount = recordCount;
}
/**
* 改写默认getPageCount方法
* @return
*/
public Integer getPageCount() {
//方法一:
if (recordCount % pageSize == 0) {
pageCount= recordCount / pageSize;
} else {
pageCount= recordCount / pageSize + 1;
}
return pageCount;
//方法二:
// return pageCount = (recordCount + pageSize - 1) / pageSize;
}
public void setPageCount(Integer pageCount) {
this.pageCount = pageCount;
}
public List<T> getPageList() {
return pageList;
}
public void setPageList(List<T> pageList) {
this.pageList = pageList;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
package com.zyp168.util;
import java.io.IOException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
/**
* 分页标签:拼写要输出到页面的HTML文本 请求地址 url 分页相关参数 page
*/
public class PageTag<T> extends SimpleTagSupport {
// 此处可以继承TagSupport或SimpleTagSupport接口(注意:Java单继承,只能继承一个)
private String url; // 请求URI
private PageModel<T> page; // 分页相关参数
public void doTag() {
JspWriter out = getJspContext().getOut();// SimpleTagSupport接口
// PrintWriter out = response.getWriter();
StringBuffer buffer = new StringBuffer();
// StringBuilder sbl = new StringBuilder();
/**
* //拼写要输出到页面的HTML文本
*/
// 拼接“第一页”和“上一页”
if (page.getPageNum()==1) {
buffer.append("第一页 上一页");
}else {
buffer.append("<a href='");
buffer.append(url);
buffer.append("&pageNum=1'>第一页</a>");
buffer.append("<a href='");
buffer.append(url);
buffer.append("&pageNum=");
buffer.append(page.getPageNum()-1);
buffer.append("'>上一页</a>");
}
// 循环拼接页码
for (int i = 1; i <= page.getPageCount(); i++) {
buffer.append("<a href='");
buffer.append(url);
buffer.append("&pageNum=");
buffer.append(i);
buffer.append("'>");
buffer.append(i);
buffer.append("</a>");
}
// 拼接“下一页”和“最后一页”
if (page.getPageNum()>=page.getPageCount()) {
buffer.append("下一页 最后一页");
}else {
buffer.append("<a href='");
buffer.append(url);
buffer.append("&pageNum=");
buffer.append(page.getPageNum()+1);
buffer.append("&'>下一页</a>");
buffer.append("<a href='");
buffer.append(url);
buffer.append("&pageNum=");
buffer.append(page.getPageCount());
buffer.append("'>最后一页</a>");
}
// 拼接共*页
buffer.append(" 共");
buffer.append(page.getPageCount());
buffer.append("页");
// 向页面输出分页的内容
try {
out.print(buffer.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
//
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public PageModel<T> getPage() {
return page;
}
public void setPage(PageModel<T> page) {
this.page = page;
}
}
Web中servlet部分实例:
(1)建议大家将所有jsp页面都放入WEB-INFO下,编写URL过滤器类,并将密码采用MD5加密保证安全,此处不详叙。
(2)大家可以将字符集部分做成过滤器,没必要每次设置字符集(想下spring的字符过滤配置)
(3)建议大家使用注解方式,减少web.xml配置(想下SpringMVC的注解)
(4)截取url地址交给不同方法处理的策略模式,是否让大家想起struct 和 springmvc的风格?
(5)Java反射机制学的比较好的同志们,不如尝试下反向生成对象?(想下Spring的依赖注入和控制反转)
package com.zyp168.web.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.zyp168.model.User;
import com.zyp168.service.UserService;
import com.zyp168.service.impl.UserServiceImpl;
@WebServlet(name = "userServlet", urlPatterns = { "/user/*" })
public class UserServlet extends HttpServlet {
// 成员变量
private static final long serialVersionUID = 1L;
private UserService userService = new UserServiceImpl();
/**
* Servlet中main方法:service() doGet() doPost()等
* service()方法没有用static修饰,可以直接调用类内的非静态方法,尽量少使用static;
*/
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 字符集配置(建议放入字符集过滤器进行设置)
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
// 解析请求信息URL
String uri = request.getRequestURI();// 获取的地址为"/SOSO/user/execute.action"
String action = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf("."));
// 匹配逻辑处理方法
if ("execute".equals(action)) {
execute(request, response);
}
if ("register".equals(action)) {
register(request, response);
}
if ("login".equals(action)) {
// 第一域名相同的单点登陆SSO(Single Sign On)
login(request, response);
}
if ("repwd".equals(action)) {
repwd(request, response);
}
if ("findByCondition".equals(action)) {
findByCondition(request, response);
}
}
// 逻辑处理方法
private void execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* 访问WEB-INF的入口方法
*/
request.getRequestDispatcher("/WEB-INF/jsp/" + request.getParameter("uri")).forward(request, response);
}
private String register(HttpServletRequest request, HttpServletResponse response) {
return null;
}
private void login(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String name = request.getParameter("name");
String password = request.getParameter("password");
User model = new User();
model.setName(name);
model.setPwd(password);
if (name != null && password != null) {
User user = userService.login(model);
if (model != null) {
if (name.equals(user.getName()) && password.equals(user.getPwd())) {
HttpSession session = request.getSession();
session.setAttribute("user", user);
// SSO相关操作:写入cookie
Cookie cookie = new Cookie("sso", user.getName());
cookie.setMaxAge(3600);// 一小时
cookie.setDomain(".zyp168.com");// www.bbs.zyp168.com 和
// www.news.zyp168.com
cookie.setPath("/"); // 如果为/demo_01表示仅仅demo_01项目可以获得
response.addCookie(cookie);
response.sendRedirect("/WEB-INF/jsp/index.jsp");
}
}
}
String msg = "您输入的帐户或密码有误,请重新登陆!";
request.setAttribute("msg", msg);
request.getRequestDispatcher("/redirect.jsp").forward(request, response);
}
private String repwd(HttpServletRequest request, HttpServletResponse response) {
return null;
}
private String findByCondition(HttpServletRequest request, HttpServletResponse response) {
return null;
}
}
本文先写到这里,不足之处希望大家指出,文中实例代码仅供参考,希望大家重思想,不要纠结代码,本文有待完善,希望大家提供宝贵意见,谢谢!