项目准备
代码结构
数据库配置文件
jdbc.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/[数据库名]?rewriteBatchedStatements=true
username=root
password=Gepoint
initialSize=10
maxActive=20
maxWait=1000
filters=wall
工具类
StringUtil
/**
*[ 判断字符串是否为空]
*
* @param str
* @return
*/
public static boolean isBlank(String str) {
boolean result = false;
if (str == null || "".equals(str) || str.trim().length() == 0) {
result = true;
}
return result;
}
/**
* [判断字符串是否非空]
*
* @param str
* @return
*/
public static boolean isNotBlank(String str) {
return !isBlank(str);
}
/**
*[ 将list的内容以分隔符的形式拼接到字符串]
*
* @param list
* @param div
* 分隔符
* @return
*/
public static String joinListToString(List<String> list, String div) {
StringBuffer sb = new StringBuffer();
for (String str : list) {
sb.append(str).append(div);
}
return sb.toString().substring(0, sb.length() - div.length());
}
JDBCUtil
/**
* [负责获取和关闭数据库连接]
*
* @author houjiahui
*
*/
public class JDBCUtil
{
/**
* [ 获取数据库连接对象]
*
* @return
* @throws SQLException
*/
public static Connection getDruidConnecton() {
Connection conn = null;
try {
conn = DSUtil.getDruidDataSource().getConnection();
}
catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
/**
* [关闭ResultSet,PreparedStatement,Connection对象]
*
* @param rs
* @param ps
* @param conn
*/
public static void CloseConnection(ResultSet rs, PreparedStatement ps, Connection conn) {
if (rs != null) {
try {
rs.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
if (ps != null) {
try {
ps.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
}
}
DSUtil
public class DSUtil
{
// 配置静态数据库连接池
private static DataSource ds;
/**
* [获取连接池对象]
* @return
*/
public static DataSource getDruidDataSource() {
try {
Properties pro = new Properties();
pro.load(JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties"));
ds = DruidDataSourceFactory.createDataSource(pro);
}catch (Exception e) {
e.printStackTrace();
}
return ds;
}
}
DBUtils
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
/**
* [负责一些通用的增删改查操作]
*
* @author houjiahui
*
*/
public class DBUtils
{
/**
* [通用的查询操作]
* @param connection 用于事务操作
* @param clazz 传入实例类
* @param sql
* @param args
* @return 查多条就直接返回,查单条就get(0)
*/
public static <T> List<T> getInstance(Connection connection, Class<T> clazz, String sql, Object... args) {
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
ArrayList<T> arr = new ArrayList<>();
try {
preparedStatement = connection.prepareStatement(sql);
// 填充占位符
for (int i = 0; i < args.length; i++) {
preparedStatement.setObject(i + 1, args[i]);
}
resultSet = preparedStatement.executeQuery();
// 获取结果集列数,封装在元数据中
ResultSetMetaData metaData = resultSet.getMetaData();
// 通过resultSetMetaData获取结果集列数
int columnCount = metaData.getColumnCount();
while (resultSet.next()) {
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
// 获取列的值
Object value = resultSet.getObject(i + 1);
// 获取列名
String columnName = metaData.getColumnLabel(i + 1);
// System.out.println(columnName);
// 加载运行时类的属性
Field field = clazz.getDeclaredField(columnName);
// 保证属性可访问
field.setAccessible(true);
field.set(t, value);
}
arr.add(t);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
JDBCUtil.CloseConnection(resultSet, preparedStatement, null);
}
return arr;
}
/**
* [通用的增、删、改操作,带事务处理]
*
* @param sql
* @param args
*/
public int update(Connection connection, String sql, Object... args) {
PreparedStatement ps = null;
int c = 0;
try {
// 获取PreparedStatement的实例
ps = connection.prepareStatement(sql);
// 填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i + 1, args[i]);
}
// 执行sql语句
c = ps.executeUpdate();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
// 关闭资源
JDBCUtil.CloseConnection(null, ps, null);
}
return c;
}
}
所需的pom文件
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 控制编译版本(否则每次工程update的时候,编译版本都会恢复到1.5 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- tomcat插件配置 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8099</port>
</configuration>
</plugin>
</plugins>
</build>
处理字符编码的过滤器
EncodingFilter
@WebFilter("/*")
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
所需的miniui资源文件
项目创建
miniui
通用
按钮
<a class="mini-button" onclick="search()">查询</a>
拼串
'<a class="mini-button" onclick="editBookInfo(\''+bookid+'\')">编辑</a>'
列表
表单
下拉框mini-combobox
注意valueField和textField映射的值,数据加载地址可以写文件也可以发送请求
<input id="bookTypeSearch" name="bookTypeSearch" emptyText="请输入图书类别" class="mini-combobox" showNullItem="true" allowInput="true" nullItemText="--请选择类别--" url="../../data/booktype.txt" textField="text" valueField="id" />
请求文件格式
[
{ "id": "1", "text": "文学类" },
{ "id": "2", "text": "科技类" },
{ "id": "3", "text": "艺术类" },
{ "id": "4", "text": "其他类" }
]
文本输入框textbox
<input name="bookname" class="mini-textbox" required="true" emptyText="请输入图书名称" requiredErrorText="你忘记输入图书名称了" />
点选数字spinner
<input name="remain" class="mini-spinner" value="10" minValue="1" maxValue="200" />
时间datepicker
一定要记得格式化
前台
<input id="borrowtime" class="mini-datepicker" style="width: 200px" onvaluechanged="onValueChanged" nullValue="null" format="yyyy-MM-dd H:mm:ss" timeFormat="H:mm:ss" showTime="true" showOkButton="true" showClearButton="false" allowInput="false"/>
后台
HashMap<String, Object> hashMap = new HashMap<String, Object>();
hashMap.put("total", total);
hashMap.put("data", borrowllist);
String json = JSONObject.toJSONStringWithDateFormat(hashMap, "yyyy-MM-dd HH:mm:ss");
response.getWriter().write(json);
单选radiobuttonlist
<input id="country" name="country" class="mini-radiobuttonlist"
url="../../data/countrys.txt" textField="text" valueField="id" />
典型页面
1.OutlookMenu
主要修改折叠菜单和iframe的指向
欢迎页面的指向
左侧菜单布局和指向
菜单配置文件
[
{ id: "bookinfo", text: "图书信息管理", iconCls: "icon-folder"},
{ id: "addBookinfo", pid: "bookinfo", text: "图书列表", iconCls: "icon-add", url: "./pages/bookinfo/bookinfolist.html" },
{ id: "borrowinfo", text: "借阅信息管理", iconCls: "icon-folder"},
{ id: "addBorrowinfo", pid: "borrowinfo", text: "借阅列表", iconCls: "icon-add", url: "./pages/borrowinfo/borrowinfolist.html" },
]
2.新增页面
典型事件
开始的表格数据加载(带排序的)
可以加上keywords来实现关键字查询
需要四个参数(pageIndex, pageSize, sortField, sortOrder)
前台需要的设置:
grid.sortBy("borrowtime", "desc");
或者在div中加属性:
<div id="datagrid1" class="mini-datagrid" style="width: 100%; height: 100%" allowResize="false"
url="../../borrowinfolistaction?method=queryborrowinfo" idField="id" multiSelect="true" sizeList="[5,10,20,50]"
pageSize="10" sortField="borrowtime" sortOrser="desc">
<!--表格内容-->
</div>
注意前后台传值的大小写对应
渲染列表项目
renderer="onxxxRenderer"
//获取类别选项
function getBookTypeData() {
$.ajax({
url: "../../data/booktype.txt",
success: function (text) {
// 解析成object对象
bookType = mini.decode(text);
},
error: function () {
}
});
}
// 渲染图书类别
function onBookTypeRenderer(e) {
for (var i = 0, l = bookType.length; i < l; i++) {
var type = bookType[i];
if (type.id == e.value) {
return type.text;
}
}
return "";
}
渲染css样式
//渲染css样式,当前行remain颜色和背景色
function onRemainRenderer(e) {
var remain = e.value;
if (remain < 10) {
//设置字体样式
e.cellStyle = "font-weight:bold;color:red;";
//设置行样式
e.rowStyle = "background-color:yellow;";
}
//设置完格式之后要返回,不知道展示什么信息
return e.value;
}
清空列表
//清空列表
function clearForm() {
var bookname = mini.get("bookNameSearch").setValue("");
var booktype = mini.get("bookTypeSearch").setValue("");
grid.load();
}
关键字查询
grid.load
可以向服务器传数据
function search() {
var bookname = mini.get("bookNameSearch").getValue();
var booktype = mini.get("bookTypeSearch").getValue();
//这里会调用url="../../bookinfolistaction?method=queryBookinfoByKeyWords"
//load方法可以向服务器传数据,服务器端可以接受请求参数(key:value)
grid.load({ bookname: bookname, booktype: booktype });
}
对应的后台方法
需要的参数
- pageIndex—默认第一页为0
- pageSize—可以自行设置
- 自己设置的keywords,如:bookname,booktype
对应的dao方法:
//判断字符是否为空,用StringBuffer来进行sql的拼接
//
public List<BookInfo> queryBookinfoByKeyWords(int pageIndex, int pageSize, String bookname, Integer booktype);
主要片段:
StringBuffer sb = new StringBuffer();
sb.append(" select * from bookinfo where 1=1 ");
if (StringUtil.isNotBlank(bookname)) {
sb.append(" and bookname like concat('%', ? ,'%') ");
}
if (booktype != null) {
sb.append(" and booktype = ? ");
}
sb.append(" limit ?,?");
String sql = sb.toString();
int i = 1;
try {
ps = con.prepareStatement(sql);
if (StringUtil.isNotBlank(bookname)) {
ps.setString(i++, bookname);
}
if (booktype != null) {
ps.setInt(i++, booktype);
}
ps.setInt(i++, indexnum);
ps.setInt(i++, pageSize);
新增操作(弹出)
//新增图书页
function add() {
mini.open({
url: bootPATH + "../pages/bookinfo/bookinfoadd.html",
title: "新增图书信息",
width: 600,
height: 400,
onload: function () {
var iframe = this.getIFrameEl();
var data = { action: "new" };
iframe.contentWindow.SetData(data);
},
ondestroy: function (action) {
grid.reload();
}
});
}
编辑页面设置初始数据
//标准方法接口定义
//加载编辑页面的时候默认填充数据
function SetData(data) {
//跨页面传递的数据对象,克隆后才可以安全使用
data = mini.clone(data);
$.ajax({
url:
"../../bookinfoeditaction?method=queryBookInfoByID&bookId=" +
data.bookId,
cache: false,
success: function (text) {
var o = mini.decode(text);
form.setData(o);
form.setChanged(false); //设置当前表单未修改的状态
},
error: function () {
alert("表单加载错误");
}
});
}
数据修改未保存的操作
//改变较多,参考原生代码修改,运用miniui自己的弹窗提示
//点击取消按钮的时候进行的操作
function onCancel(e) {
//表单被改变的操作
if (form.isChanged()) {
mini.confirm(
"数据被修改了,是否先保存?",
"提醒:",
function (action) {
//console.log(action);
//["ok", "no", "cancel"]
if (action == "ok") {
//点击确定就保存数据
SaveData();
} else {
//点击取消就关闭窗口
CloseWindow("cancel");
}
}
);
} else {
//数据未被修改的操作
CloseWindow("cancel");
}
}
详情页渲染(利用修改页面)
labelModel();
//渲染只读模式
function labelModel() {
var fields = form.getFields();
for (var i = 0, l = fields.length; i < l; i++) {
var c = fields[i];
if (c.setReadOnly) c.setReadOnly(true); //只读
if (c.setIsValid) c.setIsValid(true); //去除错误提示
if (c.addCls) c.addCls("asLabel"); //增加asLabel外观
}
}
<style type="text/css">
html,
body {
padding: 0 5px;
margin: 0;
border: 0;
height: 100%;
overflow: hidden;
}
.asLabel .mini-textbox-border,
.asLabel .mini-textbox-input,
.asLabel .mini-buttonedit-border,
.asLabel .mini-buttonedit-input,
.asLabel .mini-textboxlist-border {
border: 0;
background: none;
cursor: default;
}
.asLabel .mini-buttonedit-button,
.asLabel .mini-textboxlist-close {
display: none;
}
.asLabel .mini-textboxlist-item {
padding-right: 8px;
}
</style>
动态按钮渲染
//渲染操作按钮
function onOptionButtonRenderer(e) {
var borrowid = e.row.borrowid;
var returntime = e.row.returntime;
var str;
var str1;
str =
'<a class="mini-button" οnclick="deleteBorrowInfo(\'' +
borrowid +
"')\">删除</a>";
str1 =
'<a class="mini-button" οnclick="returnBook(\'' +
borrowid +
"')\">还书</a>";
if (returntime) {
return str;
} else {
return str1;
}
}
自动生成编号
数据库生成
select concat('Borrow',year(now()),lpad(right(ifnull(max(b.borrowid),0) ,4)+1,4,0)) from borrowinfo b
where mid(borrowid,7,4)=year(now());
setFormValue();
//新增时自动生成borrowid
function setFormValue() {
$.ajax({
url: "../../borrowinfoaddaction?method=getnextborrowid",
type: "post",
cache: false,
success: function (text) {
//设置借阅编号
mini.get("borrowid").setValue(text);
//设置借阅时间
mini.get("borrowtime").setValue(new Date());
},
error: function (jqXHR, textStatus, errorThrown) {
alert(jqXHR.responseText);
mini.alert(textStatus, "提示:", function () {
CloseWindow();
});
}
});
}
数据联动
//数据联动用onvalueChanged,当下拉框改变的时候,输入框自动写入剩余数量
function onBookIdChanged(e) {
//方法2:简便
//var remain = e.selected.remian;
var bookId = e.value;
$.ajax({
url:
"../../bookinfolistaction?method=queryreaminbybookid&bookid=" +
bookId,
type: "post",
cache: false,
success: function (text) {
mini.get("remain").setValue(text);
},
error: function (jqXHR, textStatus, errorThrown) {
alert(jqXHR.responseText);
mini.alert(textStatus, "提示:", function () {
CloseWindow();
});
}
});
}
行内点击时填充相应数据
//图书借阅页面
function borrowBookInfo(bookId) {
mini.open({
url: bootPATH + "../pages/borrowinfo/borrowinfoadd.html",
title: "图书借阅",
width: 600,
height: 400,
onload: function () {
var iframe = this.getIFrameEl();
var data = { bookId: bookId, action: "listButton" };
iframe.contentWindow.SetData(data);
},
ondestroy: function (action) {
grid.reload();
}
});
}
//当行内点击时候才会填充数据,bookinfolist来调用的
function SetData(data) {
if (data.action == "listButton") {
//跨页面传递的数据对象,克隆后才可以安全使用
data = mini.clone(data);
var bookId = data.bookId;
$.ajax({
url:
"../../borrowinfoaddaction?method=getbookbyid&bookid=" + bookId,
cache: false,
success: function (text) {
var o = mini.decode(text);
mini.getbyName("bookid").setValue(o.bookid);
mini.getbyName("bookid").setText(o.bookname);
mini.getbyName("bookid").setEnabled(false);
mini.getbyName("remain").setValue(o.remain);
},
error: function (jqXHR, textStatus, errorThrown) {
alert(jqXHR.responseText);
mini.alert(textStatus, "提示:", function () {
CloseWindow();
});
}
});
}
}
删除操作(单选+多选)
删除的时候进行提示,确定则删除
将选择的id封装程 aa,bb,cc的数组传到后台
//单选+多选删除数据
function deleteBookInfo() {
var rows = grid.getSelecteds();
if (rows.length > 0) {
mini.confirm("确定删除选中记录?", "提示信息:", function (action) {
if (action == "ok") {
var ids = [];
for (var i = 0, l = rows.length; i < l; i++) {
var r = rows[i];
ids.push(r.bookid);
}
var bookids = ids.join(",");
grid.loading("操作中,请稍后......");
$.ajax({
url:
"../../bookinfolistaction?method=deletebookinfo&bookids=" +
bookids,
success: function (text) {
mini.alert(text);
grid.reload();
},
error: function () {
}
});
}
});
} else {
mini.alert("请选中一条记录!");
}
}
后台解析并级联删除
级联操作示例:
dao层
int i = 0;//记录操作a成功条数
int j = 0;//记录操作b成功条数
int result = 0;//记录a,b都成功的条数,当都成功时候才会提交
String sql = " DELETE FROM bookinfo WHERE bookid=? ";
String sql2 = "delete from borrowinfo where bookid=?";
connection.setAutoCommit(false);
//直接级联操作,
//失败就回滚
//成功就提交
service层
ArrayList<String> deleteSuccess = new ArrayList<String>();
ArrayList<String> deleteFail = new ArrayList<String>();
ArrayList<String> deleteError = new ArrayList<String>();
String[] split = bookIds.split(",");
for (String bookid : split) {......}
//利用工具类进行拼串
StringBuffer result = new StringBuffer();
....
return result.toString();
接口定义
dao层
bookinfo
public int addBookInfo(BookInfo bookInfo);
public int updateBookInfo(BookInfo bookInfo);
public int deleteBookinfo(String bookIds);
public int deleteBookinfoById(String bookId);
public BookInfo queryBookInfoByID(String bookId);
public List<BookInfo> queryBookinfoByKeyWords(int pageIndex, int pageSize, String bookname, Integer booktype);
public int findLength();
public BookInfo checkExist(String booknamebefore, String booknamenow, String author);
borrowinfo
常见问题
时间格式获取的时候出现.0的情况
String sql = "select * from borrowinfo ";
List<BorrowInfo> bookInfos = getInstance(BorrowInfo.class, sql);
// 处理时间后面有个.0的问题
Date borrowtime = bookInfos.get(0).getBorrowtime();
DateFormat dateTimeInstance = DateFormat.getDateTimeInstance();
String format = dateTimeInstance.format(borrowtime);
System.out.println(format);
时间格式设置获取
borrowInfo.setBorrowtime(rs.getTimestamp("borrowtime"));
prepareStatement.setObject(5, new Date());
前后台时间格式
要统一,见上面
数据格式对应
datetime–Timestamp