LayUI后台管理与综合示例

2023-05-10

一、LayUI介绍

layui(谐音:类UI) 是一款采用自身模块规范编写的前端 UI 框架,遵循原生 HTML/CSS/JS 的书写与组织形式,门槛极低,拿来即用。其外在极简,却又不失饱满的内在,体积轻盈,组件丰盈,从核心代码到 API 的每一处细节都经过精心雕琢,非常适合界面的快速开发。layui 首个版本发布于2016年金秋,她区别于那些基于 MVVM 底层的 UI 框架,却并非逆道而行,而是信奉返璞归真之道。准确地说,她更多是为服务端程序员量身定做,你无需涉足各种前端工具的复杂配置,只需面对浏览器本身,让一切你所需要的元素与交互,从这里信手拈来。

layui 兼容人类正在使用的全部浏览器(IE6/7除外),可作为 PC 端后台系统与前台界面的速成开发方案。

1.1、资源

文档:http://www.layui.com/doc/

官网:http://www.layui.com/

git:https://github.com/sentsin/layui

二、Hello World

2.1、引入UI框架

下载layui将dest中的内容添加到项目中

项目:

2.2、后台布局

新建admin.html

<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>layout 后台大布局 - Layui</title>
<link rel="stylesheet" href="js/layui/css/layui.css">
</head> <body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo">layui 后台布局</div>
<!-- 头部区域(可配合layui已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item">
<a href="">控制台</a>
</li>
<li class="layui-nav-item">
<a href="">商品管理</a>
</li>
<li class="layui-nav-item">
<a href="">用户</a>
</li>
<li class="layui-nav-item">
<a href="javascript:;">其它系统</a>
<dl class="layui-nav-child">
<dd>
<a href="">邮件管理</a>
</dd>
<dd>
<a href="">消息管理</a>
</dd>
<dd>
<a href="">授权管理</a>
</dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">
<img src="http://t.cn/RCzsdCq" class="layui-nav-img"> 贤心
</a>
<dl class="layui-nav-child">
<dd>
<a href="">基本资料</a>
</dd>
<dd>
<a href="">安全设置</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="">退了</a>
</li>
</ul>
</div> <div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;">所有商品</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;">列表一</a>
</dd>
<dd>
<a href="javascript:;">列表二</a>
</dd>
<dd>
<a href="javascript:;">列表三</a>
</dd>
<dd>
<a href="http://www.baidu.com">超链接</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;">解决方案</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;">列表一</a>
</dd>
<dd>
<a href="javascript:;">列表二</a>
</dd>
<dd>
<a href="">超链接</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="">云市场</a>
</li>
<li class="layui-nav-item">
<a href="">发布商品</a>
</li>
</ul>
</div>
</div> <div class="layui-body">
<!-- 内容主体区域 -->
<div style="padding: 15px;"> <table id="demo" lay-filter="test"></table> </div>
</div> <div class="layui-footer">
<!-- 底部固定区域 -->
© layui.com - 底部固定区域
</div>
</div>
<script src="js/layui/layui.all.js"></script>
<script>
//JavaScript代码区域
layui.use('element', function() {
var element = layui.element; }); layui.use('table', function(){
var table = layui.table; //第一个实例
table.render({
elem: '#demo'
,height: 315
,url: '/demo/table/user/' //数据接口
,page: true //开启分页
,cols: [[ //表头
{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left'}
,{field: 'username', title: '用户名', width:80}
,{field: 'sex', title: '性别', width:80, sort: true}
,{field: 'city', title: '城市', width:80}
,{field: 'sign', title: '签名', width: 177}
,{field: 'experience', title: '积分', width: 80, sort: true}
,{field: 'score', title: '评分', width: 80, sort: true}
,{field: 'classify', title: '职业', width: 80}
,{field: 'wealth', title: '财富', width: 135, sort: true}
]]
}); });
</script>
</body> </html>

结果

2.3、后台服务

2.3.1、封装数据R.java

package com.zhangguo.utils;

public class R {
/**响应编码*/
private int code;
/**响应消息*/
private String msg;
/**数据总量*/
private int count;
/**数据*/
private Object data; public R() {
} public R(int code, String msg, int count, Object data) {
super();
this.code = code;
this.msg = msg;
this.count = count;
this.data = data;
} @Override
public String toString() {
return "R [code=" + code + ", msg=" + msg + ", count=" + count + ", data=" + data + "]";
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} public Object getData() {
return data;
} public void setData(Object data) {
this.data = data;
} }

2.3.2、数据访问UserDao.java

package com.zhangguo.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID; import com.zhangguo.entity.User; /**
* 用户数据访问
*/
public class UserDao {
private static List<User> users = new ArrayList<>(); static { for (int i = 1; i <= 500; i += 3) {
users.add(new User(i, "张国立" + UUID.randomUUID(), "中国北京" + UUID.randomUUID()));
users.add(new User(i + 1, "张学友" + UUID.randomUUID(), "中国香港" + UUID.randomUUID()));
users.add(new User(i + 2, "张慧妹" + UUID.randomUUID(), "中国珠海" + UUID.randomUUID()));
}
} //http://www.layui.com/demo/table/user/?page=1&limit=10 /** 获得所有用户 */
public List<User> getPager(int page,int limit) {
List<User> list = new ArrayList<>();
int start=(page-1)*limit;
for (int i =start; i <start+limit&&i<users.size(); i++) {
list.add(users.get(i));
}
return list;
} /** 获得所有用户 */
public List<User> getAllUsers() {
return users;
} /** 添加用户 */
public void addUser(User user) {
if (user.getId() <= 0) { // 未设置id
int index = users.size() - 1; // 获得最后一个用户的索引号
if (index < 0) { // 如没有一个用户
user.setId(1); // 编号为1
} else {
user.setId(users.get(index).getId() + 1); // 获得最后一个用户的编号+1
}
}
users.add(user);
} /** 删除用户 */
public void delUser(int id) {
User delUser = null;
for (User user : users) {
if (user.getId() == id) {
delUser = user;
break;
}
}
users.remove(delUser);
} public void updateUser(User obj) {
User editUser = null;
for (User user : users) {
if (user.getId() == obj.getId()) {
editUser = user;
break;
}
}
editUser.setName(obj.getName());
editUser.setCity(obj.getCity());
} }

2.3.3、分页服务

package com.zhangguo.action;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.zhangguo.dao.UserDao;
import com.zhangguo.entity.User;
import com.zhangguo.test.JsonUtils;
import com.zhangguo.utils.R; /**
* 用户控制器
*/
@WebServlet("/UserController")
public class UserController extends HttpServlet {
private static final long serialVersionUID = 1L; private UserDao userDao = new UserDao(); protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
request.setCharacterEncoding("utf-8"); String action = request.getParameter("action"); if (action.equals("list")) {
list(response); //获得所有用户
}else if (action.equals("add")) {
add(request, response); //添加新用户
}
else if (action.equals("del")) { //删除用户
delUser(request, response);
}
else if (action.equals("update")) { //更新用户
int id =Integer.parseInt(request.getParameter("id"));
String name = request.getParameter("name");
String city = request.getParameter("city");
userDao.updateUser(new User(id,name, city)); delay();
response.getWriter().print("{\"msg\":\"更新成功\"}");
}
else if (action.equals("pager")) { //分页
int page =Integer.parseInt(request.getParameter("page"));
int limit =Integer.parseInt(request.getParameter("limit")); R r=new R();
r.setCode(0);
r.setMsg("获得数据成功");
r.setCount(500);
r.setData(userDao.getPager(page, limit)); delay();
response.getWriter().print(JsonUtils.toJson(r));
}
} /**删除用户*/
public void delUser(HttpServletRequest request, HttpServletResponse response) throws IOException {
int id =Integer.parseInt(request.getParameter("id"));
userDao.delUser(id);
delay();
response.getWriter().print("{\"msg\":\"删除成功\"}");
} /**添加新用户*/
public void add(HttpServletRequest request, HttpServletResponse response) throws IOException {
String name = request.getParameter("name");
String city = request.getParameter("city");
userDao.addUser(new User(name, city)); delay();
response.getWriter().print("{\"msg\":\"添加成功\"}");
} /**获得所有用户*/
public void list(HttpServletResponse response) throws IOException { //Java 对象 - > 字符串 序列化成JSON
//字符串 -> Java对象 反序列化 String result = "[";
for (User user : userDao.getAllUsers()) {
result += "{\"id\":" + user.getId() + ",\"name\":\"" + user.getName() + "\",\"city\":\""
+ user.getCity() + "\"},";
}
if (result.substring(result.length() - 1, result.length()).equals(",")) {
result = result.substring(0, result.length() - 1);
}
result += "]"; delay();
response.getWriter().print(result);
} public void delay(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
} }

2.3.4、服务测试

2.3.5、对接前后台

<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>layout 后台大布局 - Layui</title>
<link rel="stylesheet" href="js/layui/css/layui.css">
</head> <body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo">layui 后台布局</div>
<!-- 头部区域(可配合layui已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item">
<a href="">控制台</a>
</li>
<li class="layui-nav-item">
<a href="">商品管理</a>
</li>
<li class="layui-nav-item">
<a href="">用户</a>
</li>
<li class="layui-nav-item">
<a href="javascript:;">其它系统</a>
<dl class="layui-nav-child">
<dd>
<a href="">邮件管理</a>
</dd>
<dd>
<a href="">消息管理</a>
</dd>
<dd>
<a href="">授权管理</a>
</dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">
<img src="http://t.cn/RCzsdCq" class="layui-nav-img"> 贤心
</a>
<dl class="layui-nav-child">
<dd>
<a href="">基本资料</a>
</dd>
<dd>
<a href="">安全设置</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="">退了</a>
</li>
</ul>
</div> <div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;">所有商品</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;">列表一</a>
</dd>
<dd>
<a href="javascript:;">列表二</a>
</dd>
<dd>
<a href="javascript:;">列表三</a>
</dd>
<dd>
<a href="http://www.baidu.com">超链接</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;">解决方案</a>
<dl class="layui-nav-child">
<dd>
<a href="javascript:;">列表一</a>
</dd>
<dd>
<a href="javascript:;">列表二</a>
</dd>
<dd>
<a href="">超链接</a>
</dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="">云市场</a>
</li>
<li class="layui-nav-item">
<a href="">发布商品</a>
</li>
</ul>
</div>
</div> <div class="layui-body">
<!-- 内容主体区域 -->
<div style="padding: 15px;"> <table id="users" lay-filter="test"></table> </div>
</div> <div class="layui-footer">
<!-- 底部固定区域 -->
© layui.com - 底部固定区域
</div>
</div>
<script src="js/layui/layui.all.js"></script>
<script>
//JavaScript代码区域
layui.use('element', function() {
var element = layui.element; }); layui.use('table', function(){
var table = layui.table; //第一个实例
table.render({
elem: '#users'
,height: 515
,url: 'UserController?action=pager' //数据接口
,page: true //开启分页
,cols: [[ //表头
{field: 'id', title: 'ID', width:80, sort: true, fixed: 'left'}
,{field: 'name', title: '用户名', width:300,sort: true}
,{field: 'city', title: '城市', width:300,sort: true}
,{field: 'birthday', title: '出生日期', width: 177,sort: true}
]]
}); });
</script>
</body> </html>

2.3.6、运行结果

三、综合示例

3.1、概要

实现商品的后台管理功能,添加,修改,删除,更新,上传,富文本,前台展示,手机端的浏览

3.2、创建数据库

--商品
--编号,名称,价格,上架时间,状态,图片 --创建数据库
create database GoMallPro; use GoMallPro; --创建表
create table Product
(
id int primary key identity(100000,1),
name nvarchar(256) not null,
price decimal(9,2),
addDate datetime,
[state] int default(1),
picture varchar(126)
) --添加数据
INSERT INTO [GoMallPro].[dbo].[Product]
([name]
,[price]
,[addDate]
,[state]
,[picture])
select 'iPhone X',5898.5,GETDATE(),1,'pic(1).jpg' union
select 'Meizu 魅蓝1',999.9,'2014-01-12',1,'pic(2).jpg' union
select 'ZTE U880',566.85,GETDATE(),0,'pic(3).jpg' union
select '华为 荣耀6',1487.3,'2018-04-15',1,'pic(4).jpg' union
select '小米 Max 2',1398.2,'2017-12-09',0,'pic(5).jpg' SELECT [id] ,[name],[price] ,[addDate],[state],[picture] FROM [Product]

结果:

3.3、创建项目

创建一个web项目,记得选择生成web.xml文件

创建完成

在webcontent目录下添加images图片目录

在webcontent目录下添加layui 后台模板

添加后的效果

部署运行

创建页,未修改的模板

后台管理

3.4、创建实体类

Product.java

package com.zhangguo.gomallpro.model;

import java.math.BigDecimal;
import java.util.Date; /**
* 产品 Bean
* */
public class Product {
private int id;
private String name;
private BigDecimal price;
private Date addDate;
private int state;
private String picture; public Product() {
} public Product(int id, String name, BigDecimal price, Date addDate, int state, String picture) {
super();
this.id = id;
this.name = name;
this.price = price;
this.addDate = addDate;
this.state = state;
this.picture = picture;
} @Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", price=" + price + ", addDate=" + addDate + ", state=" + state
+ ", picture=" + picture + "]";
} public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public Date getAddDate() {
return addDate;
}
public void setAddDate(Date addDate) {
this.addDate = addDate;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getPicture() {
return picture;
}
public void setPicture(String picture) {
this.picture = picture;
} }

3.5、数据访问

ProductDao.java

先添加依赖包sqljdbc4.jar

JDBCUitls工具类

package com.zhangguo.gomallpro.utils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class JDBCUtils { public static String DRIVER = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
public static String URL = "jdbc:sqlserver://localhost:1433;databasename=GoMallPro";
public static String USER_NAME = "sa";
public static String PASSWORD = "sa"; static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} private JDBCUtils() { } /**
* Get connection
*
* @return
*/
public static Connection getconnnection() {
Connection con = null;
try {
con = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
} catch (SQLException e) {
e.printStackTrace();
}
return con;
} /**
* Close connection
*
* @param rs
* @param st
* @param con
*/
public static void close(ResultSet rs, Statement st, Connection con) {
try {
try {
if (rs != null) {
rs.close();
}
} finally {
try {
if (st != null) {
st.close();
}
} finally {
if (con != null)
con.close();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* Close connection
*
* @param rs
*/
public static void close(ResultSet rs) {
Statement st = null;
Connection con = null;
try {
try {
if (rs != null) {
st = rs.getStatement();
rs.close();
}
} finally {
try {
if (st != null) {
con = st.getConnection();
st.close();
}
} finally {
if (con != null) {
con.close();
}
}
}
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* Close connection
*
* @param st
* @param con
*/
public static void close(Statement st, Connection con) {
try {
try {
if (st != null) {
st.close();
}
} finally {
if (con != null)
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* insert/update/delete
*
* @param sql
* @param args
* @return
*/
public static int update(String sql, Object... args) {
int result = 0;
Connection con = getconnnection();
PreparedStatement ps = null;
try {
ps = con.prepareStatement(sql);
if (args != null) {
for (int i = 0; i < args.length; i++) {
ps.setObject((i + 1), args[i]);
}
}
result = ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(ps, con);
} return result;
} /**
* query, because need to manually close the resource, so not recommended
* for use it
*
* @param sql
* @param args
* @return ResultSet
*/
@Deprecated
public static ResultSet query(String sql, Object... args) {
ResultSet result = null;
Connection con = getconnnection();
PreparedStatement ps = null;
try {
ps = con.prepareStatement(sql);
if (args != null) {
for (int i = 0; i < args.length; i++) {
ps.setObject((i + 1), args[i]);
}
}
result = ps.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return result;
} /**
* Query a single record
*
* @param sql
* @param args
* @return Map<String,Object>
*/
public static Map<String, Object> queryForMap(String sql, Object... args) {
Map<String, Object> result = new HashMap<String, Object>();
List<Map<String, Object>> list = queryForList(sql, args);
if (list.size() > 0) {
result = list.get(0);
}
return result;
} /**
* Query a single record
*
* @param sql
* @param args
* @return <T>
*/
public static <T> T queryForObject(String sql, Class<T> clz, Object... args) {
T result = null;
List<T> list = queryForList(sql, clz, args);
if (list.size() > 0) {
result = list.get(0);
}
return result;
} /**
* Query a single record
*
* @param sql
* @param args
* @return List<Map<String,Object>>
*/
public static List<Map<String, Object>> queryForList(String sql, Object... args) {
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
Connection con = null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
con = getconnnection();
ps = con.prepareStatement(sql);
if (args != null) {
for (int i = 0; i < args.length; i++) {
ps.setObject((i + 1), args[i]);
}
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
while (rs.next()) {
Map<String, Object> map = new HashMap<String, Object>();
for (int i = 1; i <= columnCount; i++) {
map.put(rsmd.getColumnLabel(i), rs.getObject(i));
}
result.add(map);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rs, ps, con);
}
return result;
} /**
* Query a single record
*
* @param sql
* @param args
* @return List<T>
*/
public static <T> List<T> queryForList(String sql, Class<T> clz, Object... args) {
List<T> result = new ArrayList<T>();
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
con = getconnnection();
ps = con.prepareStatement(sql);
if (args != null) {
for (int i = 0; i < args.length; i++) {
ps.setObject((i + 1), args[i]);
}
}
rs = ps.executeQuery();
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
while (rs.next()) {
T obj = clz.newInstance();
for (int i = 1; i <= columnCount; i++) {
String columnName = rsmd.getColumnName(i);
String methodName = "set" + columnName.substring(0, 1).toUpperCase()
+ columnName.substring(1, columnName.length());
Method method[] = clz.getMethods();
for (Method meth : method) {
if (methodName.equals(meth.getName())) {
meth.invoke(obj, rs.getObject(i));
}
}
}
result.add(obj);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
close(rs, ps, con);
}
return result;
}
}

ProductDao.java

package com.zhangguo.gomallpro.dao;

import java.util.List;

import com.zhangguo.gomallpro.model.Product;
import com.zhangguo.gomallpro.utils.JDBCUtils; public class ProductDao {
public List<Product> getPager(int page, int limit) {
// 开始索引
int start = (page - 1) * limit + 1;
// 结束索引
int end = page * limit; String sql = "select * from(SELECT [id] ,[name],[price] ,[addDate],[state],[picture],ROW_NUMBER() over(order by id desc) row FROM [Product]) t where t.row>=? and t.row<=?";
//执行查询返回List<Product>
return JDBCUtils.queryForList(sql, Product.class, start,end);
} public static void main(String[] args) {
ProductDao dao=new ProductDao();
for (Product p : dao.getPager(1, 10)) {
System.out.println(p);
}
} }

测试结果:

decimal->BigDecimal

3.6、产品展示

ProductDao.java

package com.zhangguo.gomallpro.dao;

import java.util.List;
import java.util.Map; import com.zhangguo.gomallpro.model.Product;
import com.zhangguo.gomallpro.utils.JDBCUtils; public class ProductDao {
/**产品分页列表*/
public List<Product> getPager(int page, int limit) {
// 开始索引
int start = (page - 1) * limit + 1;
// 结束索引
int end = page * limit; String sql = "select * from(SELECT [id] ,[name],[price] ,[addDate],[state],[picture],ROW_NUMBER() over(order by id desc) row FROM [Product]) t where t.row>=? and t.row<=?";
//执行查询返回List<Product>
return JDBCUtils.queryForList(sql, Product.class, start,end);
} /**获得总记录数*/
public int getCount() {
String sql="select COUNT(*) count from Product";
Map<String,Object> map=JDBCUtils.queryForMap(sql);
return (int)map.get("count");
} //JUnit
public static void main(String[] args) {
ProductDao dao=new ProductDao(); System.out.println(dao.getCount()); for (Product p : dao.getPager(2, 10)) {
System.out.println(p);
}
} }

测试:

分页工具类R.java

package com.zhangguo.gomallpro.utils;

public class R {
/**响应编码*/
private int code;
/**响应消息*/
private String msg;
/**数据总量*/
private int count;
/**数据*/
private Object data; public String toJson(){
return JsonUtils.toJson(this);
} public R() {
} public static R ok(){
return ok(0,null);
}
public static R ok(int count, Object data){
return new R(0, "操作成功!", count, data);
} public static R ok(String msg){
return new R(0,msg, 0,null);
} public static R error(int count, Object data){
return new R(1, "操作失败!", count, data);
}
public static R error(){
return error(0,null);
}
public static R error(String msg){
return new R(1, msg,0,null);
} public R(int code, String msg, int count, Object data) {
super();
this.code = code;
this.msg = msg;
this.count = count;
this.data = data;
} @Override
public String toString() {
return "R [code=" + code + ", msg=" + msg + ", count=" + count + ", data=" + data + "]";
} public int getCode() {
return code;
} public void setCode(int code) {
this.code = code;
} public String getMsg() {
return msg;
} public void setMsg(String msg) {
this.msg = msg;
} public int getCount() {
return count;
} public void setCount(int count) {
this.count = count;
} public Object getData() {
return data;
} public void setData(Object data) {
this.data = data;
} }

JsonUtil工具类

package com.zhangguo.gomallpro.utils;

import java.text.SimpleDateFormat;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper; public class JsonUtils {
/**
* 序列化成json
* */
public static String toJson(Object obj) {
// 对象映射器
ObjectMapper mapper = new ObjectMapper();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd HH:mm:ss");
mapper.setDateFormat(sdf); String result = null;
// 序列化user对象为json字符串
try {
result = mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return result;
} /**
* 反序列化成对象
* */
public static <T> T toObject(String json,Class<T> valueType) {
//对象映射器
ObjectMapper mapper=new ObjectMapper();
T result=null;
try {
result=mapper.readValue(json,valueType); }catch (Exception e) {
e.printStackTrace();
}
return result;
}
}

产品控制器,ProductController.java

package com.zhangguo.gomallpro.action;

import java.io.IOException;
import java.io.PrintWriter; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import com.zhangguo.gomallpro.dao.ProductDao;
import com.zhangguo.gomallpro.utils.R; /**
* 产品控制器
*/
@WebServlet("/ProductController")
public class ProductController extends HttpServlet {
private static final long serialVersionUID = 1L;
PrintWriter out; ProductDao dao=new ProductDao(); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //设置编码
response.setCharacterEncoding("utf-8");
request.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
out=response.getWriter();
String action=request.getParameter("action"); if(action.equals("getPager")){
int page=Integer.parseInt(request.getParameter("page"));
int limit=Integer.parseInt(request.getParameter("limit")); out.print(R.ok(dao.getCount(), dao.getPager(page, limit)).toJson()); }else{
out.print(R.error("不存在的动作"));
}
} protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
} }

测试服务

product.html

<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<title>商品管理</title>
<link rel="stylesheet" href="./plugins/layui/css/layui.css" media="all">
</head> <body>
<div style="padding: 10px 0 0 10px;">
<button class="layui-btn layui-btn-sm layui-btn-normal" id="btnAdd"
data-type="auto">添加</button>
</div> <table id="productList" lay-filter="test"></table> <script src="./plugins/layui/layui.js"></script>
<script>
layui.use('table', function() { var table = layui.table;
//第一个实例
table.render({
elem: '#productList'
,height:450
,url: 'ProductController?action=getPager' //数据接口
,page: true //开启分页
,cols: [[ //表头
{field: 'id', title: '编号', width:130, sort: true, fixed: 'left'}
,{field: 'name', title: '商品名称', width:200}
,{field: 'price', title: '价格', width:100, sort: true}
,{field: 'picture', title: '图片', width:130}
,{field: 'addDate', title: '上架时间', width: 160, sort: true}
,{field: 'state', title: '状态', width: 80}
]]
}); }); layui.use('jquery',function(){
var $=layui.jquery; $("#btnAdd").click(function() { //通过这种方式弹出的层,每当它被选择,就会置顶。
layer.open({
type: 1,
shade: [0.4, '#393D49'],
area: ['600px', '400px'],
maxmin: true,
content: $("#form1"),
zIndex: layer.zIndex, //重点1
success: function(layero) {
layer.setTop(layero); //重点2
},
btn: ['按钮一', '按钮二', '按钮三'],
yes: function(index, layero) {
//按钮【按钮一】的回调
},
btn2: function(index, layero) {
//按钮【按钮二】的回调 //return false 开启该代码可禁止点击该按钮关闭
},
btn3: function(index, layero) {
//按钮【按钮三】的回调 //return false 开启该代码可禁止点击该按钮关闭
},
cancel: function() {
//右上角关闭回调 //return false 开启该代码可禁止点击该按钮关闭
}
}); });
});
</script>
</body> <fieldset id="form1" hidden="hidden">
<legend>用户信息</legend>
<p>
<label for="name">姓名:</label> <input type="text" name="name" id="name"
placeholder="请输入姓名" /> <span id="nameMsg" class="red"></span>
</p>
<p>
<label for="city">城市:</label> <input type="text" name="city" id="city"
placeholder="请输入城市" /> <span id="cityMsg" class="red"></span>
</p>
<p>
<button type="button" id="btnSave" onclick="layer.closeAll()">保存</button>
<button type="button" id="btnUpdate">更新</button>
</p>
</fieldset> </html>

运行结果

3.7、AJAX文件异步上传

3.7.1、前端页面

html

<div class="layui-upload">
<button type="button" class="layui-btn" id="test1">上传图片</button>
<div class="layui-upload-list">
<img class="layui-upload-img" id="demo1">
<p id="demoText"></p>
</div>
</div>

js

layui.use('upload', function(){
var $ = layui.jquery
,upload = layui.upload; //普通图片上传
var uploadInst = upload.render({
elem: '#test1'
,url: 'UploadFile'
,before: function(obj){
//预读本地文件示例,不支持ie8
obj.preview(function(index, file, result){
$('#demo1').attr('src', result); //图片链接(base64)
});
}
,done: function(res){
//如果上传失败
if(res.code > 0){
return layer.msg('上传失败');
}
//上传成功
layer.msg(res.msg);
}
,error: function(){
//演示失败状态,并实现重传
var demoText = $('#demoText');
demoText.html('<span style="color: #FF5722;">上传失败</span> <a class="layui-btn layui-btn-mini demo-reload">重试</a>');
demoText.find('.demo-reload').on('click', function(){
uploadInst.upload();
});
}
});
});

3.7.2、后台服务

添加jar包的依赖

定义上传文件的Servlet

package com.zhangguo.gomallpro.action;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload; import com.zhangguo.gomallpro.utils.R; @SuppressWarnings("serial")
@WebServlet("/UploadFile")
public class UploadFile extends HttpServlet { @SuppressWarnings("unchecked")
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置编码
response.setCharacterEncoding("utf-8");
// 物理路径
String savePath = this.getServletConfig().getServletContext().getRealPath("");
savePath = savePath + "images\\";
File f1 = new File(savePath);
if (!f1.exists()) {
f1.mkdirs();
} DiskFileItemFactory fac = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(fac);
upload.setHeaderEncoding("utf-8");
List<FileItem> fileList = null;
try {
fileList = upload.parseRequest(request);
} catch (FileUploadException ex) {
return;
} Iterator<FileItem> it = fileList.iterator();
String name = "";
String extName = "";
while (it.hasNext()) {
FileItem item = it.next();
if (!item.isFormField()) {
name = item.getName();
long size = item.getSize();
String type = item.getContentType();
System.out.println(size + " " + type);
if (name == null || name.trim().equals("")) {
continue;
} // 扩展名格式:
if (name.lastIndexOf(".") >= 0) {
extName = name.substring(name.lastIndexOf("."));
} File file = null;
do {
// 生成文件名:
name = UUID.randomUUID().toString();
file = new File(savePath + name + extName);
} while (file.exists()); File saveFile = new File(savePath + name + extName);
try {
item.write(saveFile);
} catch (Exception exp) {
response.getWriter().write(exp.getMessage());
exp.printStackTrace();
}
}
} R r = new R();
r.setCode(0);
r.setMsg("上传成功");
Map<String, String> data = new HashMap<String, String>();
data.put("src", "images/" + name + extName);
data.put("name",name + extName);
r.setData(data); response.getWriter().print(r.toJson());
} }

3.7.3、演示结果

3.7.4、其它上传组件

http://www.uploadify.com

uploadify

3.8、富文本编辑器Kindeditor

KindEditor是一套开源的HTML可视化编辑器,主要用于让用户在网站上获得所见即所得编辑效果,兼容IE、Firefox、Chrome、Safari、Opera等主流浏览器。KindEditor使用JavaScript编写,可以无缝的于Java、.NET、PHP、ASP等程序接合。 KindEditor非常适合在CMS、商城、论坛、博客、Wiki、电子邮件等互联网应用上使用

1. 体积小,加载速度快,但功能十分丰富。2. 内置自定义range,完美地支持span标记。

3. 基于插件的方式设计,所有功能都是插件,增加自定义和扩展功能非常简单。

4. 修改编辑器风格很容易,只需修改一个CSS文件。

5. 支持大部分主流浏览器,比如IE、Firefox、Safari、Chrome、Opera。

官网:http://kindeditor.net

Github: https://github.com/kindsoft/kindeditor

Oschina: http://git.oschina.net/luolonghao/kindeditor

下载地址:https://github.com/kindsoft/kindeditor/releases/download/v4.1.11/kindeditor-4.1.11-zh-CN.zip

3.8.1、使用Kindeditor

1. 下载编辑器

下载 KindEditor 最新版本,下载之后打开 examples/index.html 就可以看到演示。
下载页面: http://www.kindsoft.net/down.php

2. 部署编辑器

解压 kindeditor-x.x.x.zip 文件,将所有文件上传到您的网站程序目录里,例如:http://您的域名/editor/
Note:
您可以根据需求删除以下目录后上传到服务器。
asp - ASP程序
asp.net - ASP.NET程序
php - PHP程序
jsp - JSP程序
examples - 演示文件

3. 修改HTML页面

1.在需要显示编辑器的位置添加textarea输入框。
<textarea id="editor_id" name="content" style="width:700px;height:300px;">
&lt;strong&gt;HTML内容&lt;/strong&gt;
</textarea>
Note:

id在当前页面必须是唯一的值。
在textarea里设置HTML内容即可实现编辑,在这里需要注意的是,如果从服务器端程序(ASP、PHP、ASP.NET等)直接显示内容,则必须转换HTML特殊字符(>,<,&,”)。具体请参考各语言目录下面的demo.xxx程序,目前支持ASP、ASP.NET、PHP、JSP。
在有些浏览器上不设宽度和高度可能显示有问题,所以最好设一下宽度和高度。宽度和高度可用inline样式设置,也可用 编辑器初始化参数 设置。
2.在该HTML页面添加以下脚本。
<script charset="utf-8" src="/editor/kindeditor.js"></script>
<script charset="utf-8" src="/editor/lang/zh_CN.js"></script>
<script>
var editor;
KindEditor.ready(function(K) {
editor = K.create('#editor_id');
});
</script>
Note:

第一个参数可用其它CSS选择器,匹配多个textarea时只在第一个元素上加载编辑器。
通过K.create函数的第二个参数,可以对编辑器进行配置,具体参数请参考 编辑器初始化参数 。
var options = {
cssPath : '/css/index.css',
filterMode : true
};
var editor = K.create('textarea[name="content"]', options);

4. 获取HTML数据
// 取得HTML内容
html = editor.html();

// 同步数据后可以直接取得textarea的value
editor.sync();
html = document.getElementById('editor_id').value; // 原生API
html = K('#editor_id').val(); // KindEditor Node API
html = $('#editor_id').val(); // jQuery

// 设置HTML内容
editor.html('HTML内容');
Note:

KindEditor的可视化操作在新创建的iframe上执行,代码模式下的textarea框也是新创建的,所以最后提交前需要执行 sync() 将HTML数据设置到原来的textarea。
KindEditor在默认情况下自动寻找textarea所属的form元素,找到form后onsubmit事件里添加sync函数,所以用form方式提交数据,不需要手动执行sync()函数。

3.8.2、文件上传

将依赖的jar文件放置到项目的lib目录中,3个jar文件已在kindeditor中存在

找到用于处理上传的jsp程序,根据需要修改

upload_json.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.io.*" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="org.apache.commons.fileupload.*" %>
<%@ page import="org.apache.commons.fileupload.disk.*" %>
<%@ page import="org.apache.commons.fileupload.servlet.*" %>
<%@ page import="org.json.simple.*" %>
<% /**
* KindEditor JSP
*
* 本JSP程序是演示程序,建议不要直接在实际项目中使用。
* 如果您确定直接使用本程序,使用之前请仔细确认相关安全设置。
*
*/ //文件保存目录路径
String savePath = pageContext.getServletContext().getRealPath("/") + "attached/"; //文件保存目录URL
String saveUrl = request.getContextPath() + "/attached/"; //定义允许上传的文件扩展名
HashMap<String, String> extMap = new HashMap<String, String>();
extMap.put("image", "gif,jpg,jpeg,png,bmp");
extMap.put("flash", "swf,flv");
extMap.put("media", "swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb");
extMap.put("file", "doc,docx,xls,xlsx,ppt,htm,html,txt,zip,rar,gz,bz2"); //最大文件大小
long maxSize = 1000000; response.setContentType("text/html; charset=UTF-8"); if(!ServletFileUpload.isMultipartContent(request)){
out.println(getError("请选择文件。"));
return;
}
//检查目录
File uploadDir = new File(savePath);
if(!uploadDir.isDirectory()){
out.println(getError("上传目录不存在。"));
return;
}
//检查目录写权限
if(!uploadDir.canWrite()){
out.println(getError("上传目录没有写权限。"));
return;
} String dirName = request.getParameter("dir");
if (dirName == null) {
dirName = "image";
}
if(!extMap.containsKey(dirName)){
out.println(getError("目录名不正确。"));
return;
}
//创建文件夹
savePath += dirName + "/";
saveUrl += dirName + "/";
File saveDirFile = new File(savePath);
if (!saveDirFile.exists()) {
saveDirFile.mkdirs();
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String ymd = sdf.format(new Date());
savePath += ymd + "/";
saveUrl += ymd + "/";
File dirFile = new File(savePath);
if (!dirFile.exists()) {
dirFile.mkdirs();
} FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
upload.setHeaderEncoding("UTF-8");
List items = upload.parseRequest(request);
Iterator itr = items.iterator();
while (itr.hasNext()) {
FileItem item = (FileItem) itr.next();
String fileName = item.getName();
long fileSize = item.getSize();
if (!item.isFormField()) {
//检查文件大小
if(item.getSize() > maxSize){
out.println(getError("上传文件大小超过限制。"));
return;
}
//检查扩展名
String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
if(!Arrays.<String>asList(extMap.get(dirName).split(",")).contains(fileExt)){
out.println(getError("上传文件扩展名是不允许的扩展名。\n只允许" + extMap.get(dirName) + "格式。"));
return;
} SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
String newFileName = df.format(new Date()) + "_" + new Random().nextInt(1000) + "." + fileExt;
try{
File uploadedFile = new File(savePath, newFileName);
item.write(uploadedFile);
}catch(Exception e){
out.println(getError("上传文件失败。"));
return;
} JSONObject obj = new JSONObject();
obj.put("error", 0);
obj.put("url", saveUrl + newFileName);
out.println(obj.toJSONString());
}
}
%>
<%!
private String getError(String message) {
JSONObject obj = new JSONObject();
obj.put("error", 1);
obj.put("message", message);
return obj.toJSONString();
}
%>

文件管理file_manager_json.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="java.util.*,java.io.*" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="org.json.simple.*" %>
<% /**
* KindEditor JSP
*
* 本JSP程序是演示程序,建议不要直接在实际项目中使用。
* 如果您确定直接使用本程序,使用之前请仔细确认相关安全设置。
*
*/ //根目录路径,可以指定绝对路径,比如 /var/www/attached/
String rootPath = pageContext.getServletContext().getRealPath("/") + "attached/";
//根目录URL,可以指定绝对路径,比如 http://www.yoursite.com/attached/
String rootUrl = request.getContextPath() + "/attached/";
//图片扩展名
String[] fileTypes = new String[]{"gif", "jpg", "jpeg", "png", "bmp"}; String dirName = request.getParameter("dir");
if (dirName != null) {
if(!Arrays.<String>asList(new String[]{"image", "flash", "media", "file"}).contains(dirName)){
out.println("Invalid Directory name.");
return;
}
rootPath += dirName + "/";
rootUrl += dirName + "/";
File saveDirFile = new File(rootPath);
if (!saveDirFile.exists()) {
saveDirFile.mkdirs();
}
}
//根据path参数,设置各路径和URL
String path = request.getParameter("path") != null ? request.getParameter("path") : "";
String currentPath = rootPath + path;
String currentUrl = rootUrl + path;
String currentDirPath = path;
String moveupDirPath = "";
if (!"".equals(path)) {
String str = currentDirPath.substring(0, currentDirPath.length() - 1);
moveupDirPath = str.lastIndexOf("/") >= 0 ? str.substring(0, str.lastIndexOf("/") + 1) : "";
} //排序形式,name or size or type
String order = request.getParameter("order") != null ? request.getParameter("order").toLowerCase() : "name"; //不允许使用..移动到上一级目录
if (path.indexOf("..") >= 0) {
out.println("Access is not allowed.");
return;
}
//最后一个字符不是/
if (!"".equals(path) && !path.endsWith("/")) {
out.println("Parameter is not valid.");
return;
}
//目录不存在或不是目录
File currentPathFile = new File(currentPath);
if(!currentPathFile.isDirectory()){
out.println("Directory does not exist.");
return;
} //遍历目录取的文件信息
List<Hashtable> fileList = new ArrayList<Hashtable>();
if(currentPathFile.listFiles() != null) {
for (File file : currentPathFile.listFiles()) {
Hashtable<String, Object> hash = new Hashtable<String, Object>();
String fileName = file.getName();
if(file.isDirectory()) {
hash.put("is_dir", true);
hash.put("has_file", (file.listFiles() != null));
hash.put("filesize", 0L);
hash.put("is_photo", false);
hash.put("filetype", "");
} else if(file.isFile()){
String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
hash.put("is_dir", false);
hash.put("has_file", false);
hash.put("filesize", file.length());
hash.put("is_photo", Arrays.<String>asList(fileTypes).contains(fileExt));
hash.put("filetype", fileExt);
}
hash.put("filename", fileName);
hash.put("datetime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(file.lastModified()));
fileList.add(hash);
}
} if ("size".equals(order)) {
Collections.sort(fileList, new SizeComparator());
} else if ("type".equals(order)) {
Collections.sort(fileList, new TypeComparator());
} else {
Collections.sort(fileList, new NameComparator());
}
JSONObject result = new JSONObject();
result.put("moveup_dir_path", moveupDirPath);
result.put("current_dir_path", currentDirPath);
result.put("current_url", currentUrl);
result.put("total_count", fileList.size());
result.put("file_list", fileList); response.setContentType("application/json; charset=UTF-8");
out.println(result.toJSONString());
%>
<%!
public class NameComparator implements Comparator {
public int compare(Object a, Object b) {
Hashtable hashA = (Hashtable)a;
Hashtable hashB = (Hashtable)b;
if (((Boolean)hashA.get("is_dir")) && !((Boolean)hashB.get("is_dir"))) {
return -1;
} else if (!((Boolean)hashA.get("is_dir")) && ((Boolean)hashB.get("is_dir"))) {
return 1;
} else {
return ((String)hashA.get("filename")).compareTo((String)hashB.get("filename"));
}
}
}
public class SizeComparator implements Comparator {
public int compare(Object a, Object b) {
Hashtable hashA = (Hashtable)a;
Hashtable hashB = (Hashtable)b;
if (((Boolean)hashA.get("is_dir")) && !((Boolean)hashB.get("is_dir"))) {
return -1;
} else if (!((Boolean)hashA.get("is_dir")) && ((Boolean)hashB.get("is_dir"))) {
return 1;
} else {
if (((Long)hashA.get("filesize")) > ((Long)hashB.get("filesize"))) {
return 1;
} else if (((Long)hashA.get("filesize")) < ((Long)hashB.get("filesize"))) {
return -1;
} else {
return 0;
}
}
}
}
public class TypeComparator implements Comparator {
public int compare(Object a, Object b) {
Hashtable hashA = (Hashtable)a;
Hashtable hashB = (Hashtable)b;
if (((Boolean)hashA.get("is_dir")) && !((Boolean)hashB.get("is_dir"))) {
return -1;
} else if (!((Boolean)hashA.get("is_dir")) && ((Boolean)hashB.get("is_dir"))) {
return 1;
} else {
return ((String)hashA.get("filetype")).compareTo((String)hashB.get("filetype"));
}
}
}
%>

KindEditor默认提供ASP、ASP.NET、PHP、JSP上传程序,这些程序是演示程序,建议不要直接在实际项目中使用。如果您确定直接使用本程序,使用之前请仔细确认相关安全设置。

选择程序语言?
// ASP
KindEditor.ready(function(K) {
K.create('#textarea_id', {
uploadJson : '../asp/upload_json.asp',
fileManagerJson : '../asp/file_manager_json.asp',
allowFileManager : true
});
});
// ASP.NET
KindEditor.ready(function(K) {
K.create('#textarea_id', {
uploadJson : '../asp.net/upload_json.ashx',
fileManagerJson : '../asp.net/file_manager_json.ashx',
allowFileManager : true
});
});
// JSP
KindEditor.ready(function(K) {
K.create('#textarea_id', {
uploadJson : '../jsp/upload_json.jsp',
fileManagerJson : '../jsp/file_manager_json.jsp',
allowFileManager : true
});
});
Note:

具体使用方法请参见各语言(asp、asp.net、php、jsp)目录下的demo.xxx文件。

完整示例:

<!DOCTYPE html>
<html> <head>
<meta charset="utf-8">
<title>kind editor Demo</title>
</head> <body>
<h2>富文本编辑器</h2> <div>
商品详细:
<textarea cols="80" rows="10" id="details" style="width:700px"></textarea>
<button type="button" id="btnSubmit">提交</button>
</div> <div id="divContent"></div> <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script type="text/javascript"
src="js/kindeditor4111/kindeditor-all-min.js"></script>
<script type="text/javascript" src="js/kindeditor4111/lang/zh-CN.js"></script>
<script>
var editor;
KindEditor.ready(function(K) {
editor = K.create('#details',{
uploadJson : 'js/kindeditor4111/jsp/upload_json.jsp', //上传程序
fileManagerJson : 'js/kindeditor4111/jsp/file_manager_json.jsp', //文件管理
allowFileManager : true //是否允许上传
}); //创建一个富文本编辑器
}); $("#btnSubmit").click(function(){
$("#divContent").html(editor.html());
}); </script>
</body> </html>

运行结果:

3.8.3、其它属性设置

K.options = {
designMode : true,
fullscreenMode : false,
filterMode : true,
wellFormatMode : true,
shadowMode : true,
loadStyleMode : true,
basePath : K.basePath,
themesPath : K.basePath + 'themes/',
langPath : K.basePath + 'lang/',
pluginsPath : K.basePath + 'plugins/',
themeType : 'default',
langType : 'zh-CN',
urlType : '',
newlineTag : 'p',
resizeType : 2,
syncType : 'form',
pasteType : 2,
dialogAlignType : 'page',
useContextmenu : true,
fullscreenShortcut : false,
bodyClass : 'ke-content',
indentChar : '\t',
cssPath : '',
cssData : '',
minWidth : 650,
minHeight : 100,
minChangeSize : 50,
zIndex : 811213,
items : [
'source', '|', 'undo', 'redo', '|', 'preview', 'print', 'template', 'code', 'cut', 'copy', 'paste',
'plainpaste', 'wordpaste', '|', 'justifyleft', 'justifycenter', 'justifyright',
'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
'superscript', 'clearhtml', 'quickformat', 'selectall', '|', 'fullscreen', '/',
'formatblock', 'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold',
'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', '|', 'image', 'multiimage',
'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak',
'anchor', 'link', 'unlink', '|', 'about'
],
noDisableItems : ['source', 'fullscreen'],
colorTable : [
['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'],
['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'],
['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'],
['#FFFFFF', '#CCCCCC', '#999999', '#666666', '#333333', '#000000']
],
fontSizeTable : ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px'],
htmlTags : {
font : ['id', 'class', 'color', 'size', 'face', '.background-color'],
span : [
'id', 'class', '.color', '.background-color', '.font-size', '.font-family', '.background',
'.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.line-height'
],
div : [
'id', 'class', 'align', '.border', '.margin', '.padding', '.text-align', '.color',
'.background-color', '.font-size', '.font-family', '.font-weight', '.background',
'.font-style', '.text-decoration', '.vertical-align', '.margin-left'
],
table: [
'id', 'class', 'border', 'cellspacing', 'cellpadding', 'width', 'height', 'align', 'bordercolor',
'.padding', '.margin', '.border', 'bgcolor', '.text-align', '.color', '.background-color',
'.font-size', '.font-family', '.font-weight', '.font-style', '.text-decoration', '.background',
'.width', '.height', '.border-collapse'
],
'td,th': [
'id', 'class', 'align', 'valign', 'width', 'height', 'colspan', 'rowspan', 'bgcolor',
'.text-align', '.color', '.background-color', '.font-size', '.font-family', '.font-weight',
'.font-style', '.text-decoration', '.vertical-align', '.background', '.border'
],
a : ['id', 'class', 'href', 'target', 'name'],
embed : ['id', 'class', 'src', 'width', 'height', 'type', 'loop', 'autostart', 'quality', '.width', '.height', 'align', 'allowscriptaccess', 'wmode'],
img : ['id', 'class', 'src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border'],
'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6' : [
'id', 'class', 'align', '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.background',
'.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.text-indent', '.margin-left'
],
pre : ['id', 'class'],
hr : ['id', 'class', '.page-break-after'],
'br,tbody,tr,strong,b,sub,sup,em,i,u,strike,s,del' : ['id', 'class'],
iframe : ['id', 'class', 'src', 'frameborder', 'width', 'height', '.width', '.height']
},
layout : '<div class="container"><div class="toolbar"></div><div class="edit"></div><div class="statusbar"></div></div>'
};
kindeditor API ,kindeditor使用手册,kindeditor函数,kindeditor使用,超级大收集
变量
1. KE
唯一的全局变量,也是程序的命名空间。
数据类型:Object
2. KE.version
编辑器的版本信息。
数据类型:String
3. KE.lang
编辑器的中文信息。
数据类型:Object
4. KE.scriptPath
kindeditor.js的路径。
数据类型:String
5. KE.htmlPath
编辑器的HTML页面路径。
数据类型:String
注:3.4版本已废弃。
6. KE.browser
浏览器类型和版本,分别为KE.browser.VERSION、KE.browser.IE、KE.browser.WEBKIT、 KE.browser.GECKO、KE.browser.OPERA。
数据类型:Object
注:3.4以前版本直接返回字符串,分别为"IE"、"WEBKIT"、"GECKO"、"OPERA"。
7. KE.setting
编辑器的初始化属性和其它配置。
数据类型:Object
8. KE.g
一个编辑器的变量集,包含所有编辑器属性,此外还包含以下变量,经常用KE.g[id]来表示。
例如:KE.g["content_1"].iframeDoc表示id为"content_1"的编辑器的iframe document对象。
数据类型:Object
主要变量:
container: 编辑器的外部element对象。
iframe: 编辑区域的iframe对象。
iframeWin: 编辑区域的iframe window对象。
iframeDoc: 编辑区域的iframe document对象。
keSel: 当前选中信息的KE.selection对象。
keRange: 当前选中信息的KE.range对象。
sel: 当前选中信息的浏览器原生selection对象。
range: 当前选中信息的浏览器原生range对象。
layoutDiv: 编辑器弹出层的div对象。3.4版本已废弃。
hideDiv: 编辑器弹出层的parent div对象。
dialog: 弹出窗口的iframe对象。3.4版本已废弃。
yesButton: 弹出窗口的确定按钮input对象。
noButton: 弹出窗口的取消按钮input对象。
previewButton: 弹出窗口的预览按钮input对象。
maskDiv: 弹出窗口时灰色遮罩层的div对象。
undoStack: undo/redo的undo记录。
redoStack: undo/redo的redo记录。
9. KE.plugin
定义编辑器的插件。
数据类型:Object
函数
1. KE.$(id, doc)
取得element对象,doc.getElementById的别名。
参数:
id:String,element的id
doc:Object,element所在document对象,是可选参数,默认值为document。
返回值:
Object,element对象
2. KE.$$(name, doc)
创建element对象,doc.createElement的别名。
参数:
name:String,element的tag name
doc:Object,element所在document对象,是可选参数,默认值为document。
返回值:
Object,element对象
3. KE.event.add(el, event, listener)
添加一个事件。
参数:
el:Object,要添加事件的element对象
event:String,事件名称,可设置"click","change","mousedown"等。
listener:Function,事件处理回调函数。
返回值:无
4. KE.event.remove(el, event, listener)
删除已添加的一个事件。
参数:
el:Object,要添加事件的element对象
event:String,事件名称,可设置"click","change","mousedown"等。
listener:Function,事件处理回调函数。
返回值:无
5. KE.event.input(el, func)
添加一个编辑器输入事件。
参数:
el:Object,要添加事件的element对象
func:Function,编辑器输入内容时调用这个函数。
返回值:无
6. KE.event.ctrl(el, key, func)
添加一个Ctrl+[]事件。
参数:
el:Object,要添加事件的element对象
key:String,Ctrl组合键的字母,支持A到Z。
func:Function,按下Ctrl+[]时调用这个函数。
返回值:无
7. KE.event.ready(func)
添加一个document的DOMContentLoaded事件。
参数:
func:Function,DOM加载完成后调用这个函数。
返回值:无
8. KE.each(obj, func)
遍历一个object。
参数:
obj:Object,要遍历的object
func:Function,循环时调用这个函数,参数为object的key和value。
返回值:无
9. KE.eachNode(node, func)
遍历一个node。
参数:
node:Object,要遍历的parent node
func:Function,循环时调用这个函数,参数为node。
返回值:无
10. KE.format.getHtml(html, htmlTags)
把HTML转换成XHTML,当指定htmlTags参数时,按照htmlTags规则过滤HTML标签。
参数:
html:String,HTML文本
htmlTags:Object,过滤规则,可选参数。
返回值:
String,XHTML文本
11. KE.util.getDocumentElement()
取得document element对象。
参数:无
返回值:
Object,element对象
12. KE.util.getDocumentWidth()
取得当前页面的宽度。
参数:无
返回值:
Int,document宽度
13. KE.util.getDocumentHeight()
取得当前页面的高度。
参数:无
返回值:
Int,document高度
14. KE.util.loadStyle(path)
在当前页面加载一个CSS文件。
参数:
path:String,CSS文件的URL路径
返回值:无
15. KE.util.inArray(str, arr)
判断一个字符串是否在一个数组里。
参数:
str:String
arr:Array
返回值:
Boolean,返回true表示在数组里,返回false表示不在数组里。
16. KE.util.trim(str)
删除字符串两边的空格字符。
参数:
str:String
返回值:String
17. KE.util.getJsKey(key)
把HTML style里的CSS名转换成JavaScript属性名。例如:KE.util.getJsKey("font-size")会返回"fontSize"。
参数:
key:String
返回值:String
18. KE.util.escape(html)
转换HTML里的特殊字符。
参数:
html:String,HTML文本
返回值:String
19. KE.util.getElementPos(el)
取得指定element的坐标。
参数:
el:Object,element对象
返回值:Object
20. KE.util.getCoords(ev)
取得鼠标坐标。
参数:
ev:Object,event对象
返回值:Object
21. KE.util.setOpacity(el, opacity)
设置element的透明度。
参数:
el:Object,element对象
opacity:Int,透明度,可设置0到100的数字。
返回值:无
22. KE.util.getIframeDoc(iframe)
取得iframe document对象。
参数:
iframe:Object,iframe对象
返回值:Object
23. KE.util.rgbToHex(str)
把RGB格式的颜色转换成16进制的颜色。
参数:
str:String,RGB颜色标记
返回值:String
24. KE.util.createRange(doc)
创建指定document的range。
参数:
doc:Object,document对象
返回值:Object,range对象
25. KE.util.getFullHtml(id, tagLineMode)
取得编辑器iframe的初始化HTML文本。
参数:
id:String,编辑器的ID
tagLineMode:Boolean,true时显示模块标签的轮廓。
返回值:String
26. KE.util.getData(id)
取得编辑器的HTML内容。
参数:
id:String,编辑器的ID
返回值:String
27. KE.util.getSrcData(id)
取得编辑器的原生HTML内容,也就是innerHTML直接返回的HTML。
参数:
id:String,编辑器的ID
返回值:String
28. KE.util.getPureData(id)
取得编辑器的纯文本内容,不包含HTML标签。3.4版本开始包含img和embed标签。
参数:
id:String,编辑器的ID
返回值:String
29. KE.util.setData(id)
把编辑器的内容设置到原TEXTAREA控件里。
参数:
id:String,编辑器的ID
返回值:无
30. KE.util.focus(id)
把焦点移到编辑器里。
参数:
id:String,编辑器的ID
返回值:无
31. KE.util.selection(id)
把当前选中信息设置到KE.g[id].sel,KE.g[id].range,KE.g[id].keSel,KE.g[id].keRange里。
参数:
id:String,编辑器的ID
返回值:无
32. KE.util.select(id)
重新选中range,仅在IE有效。
参数:
id:String,编辑器的ID
返回值:无
33. KE.util.pToBr(id)
按下回车键时生成BR标签,仅在IE有效。
参数:
id:String,编辑器的ID
返回值:无
注:3.4版本已废弃。
34. KE.util.execCommand(id, cmd, value)
执行浏览器自带的命令,详细请参考浏览器API里的document.execCommand。
参数:
id:String,编辑器的ID
cmd:String,浏览器execCommand里的cmd参数
value:String,浏览器execCommand里的value参数
返回值:无
35. KE.util.insertHtml(id, html)
把HTML内容插入到编辑区域里的光标处。
参数:
id:String,编辑器的ID
html:String,HTML内容
返回值:无
注:执行本函数之前必须先执行过 KE.util.selection(id),因为要先设置KE.g[id].sel和KE.g[id].range。
36. KE.create(id, mode)
创建编辑器。
参数:
id:String,编辑器的ID
mode:Int,可选参数,指定1时在body下面创建编辑器,0或未指定时在TEXTAREA前面创建编辑器。
返回值:无
37. KE.remove(id, mode)
移除编辑器。
参数:
id:String,编辑器的ID
mode:Int,可选参数,指定1时移除在body下面的编辑器,0或未指定时移除在TEXTAREA前面的编辑器。
返回值:无
38. KE.init(config)
设置编辑器的初始化参数。
参数:
config:Object,编辑器属性的哈希数组,具体请参考编辑器属性
返回值:无
39. KE.show(config)
初始化并创建编辑器。执行本函数时先调用KE.init设置初始化参数,然后在DOM加载完成后执行KE.create。
参数:
config:Object,编辑器属性的哈希数组,具体请参考编辑器属性
返回值:无

1. KE.selection(win, doc)
KindEditor的selection类,取得或设置选中部分的range。
参数:
win:Object,window对象
oc:Object,document对象
成员变量:
sel:Object,浏览器原生selection对象
range:Object,当前selection的浏览器原生range对象
keRange:Object,当前selection的KindEditor range对象,请参考KE.range。
方法:
addRange(keRange):设置当前selection。
focus():重新选中、仅在IE有效。
2. KE.range(doc)
KindEditor的range类,为各浏览器提供统一的range接口。
参数:
doc:Object,document对象
成员变量:
startNode:Object,开始节点
startPos:Int,开始节点的位置
endNode:Object,结束节点
endPos:Int,结束节点的位置
方法:
getParentElement():返回包含range的parent element。
getNodeList():返回range里的node list。
comparePoints(how, range):比较2个keRange的位置,how可以设置"START_TO_START", "START_TO_END", "END_TO_START","END_TO_END"。
setStart(node, pos):设置range的开始节点和位置。
setEnd(node, pos):设置range的结束节点和位置。
selectNode(node):把node设置到range,开始节点和结束节点都是node。
extractContents():提取range的内容。
cloneContents():复制range的内容。
getText():取得range的纯文本内容。
3. KE.cmd(id)
KindEditor的命令类,类似execCommand。
参数:
id:String,编辑器的ID
成员变量:
doc:Object,编辑器的iframe document对象
keSel:Int,KindEditor selection对象
keRange:Object,当前selection的KindEditor range对象
方法:
wrap(tagName, attributes):用指定标签包当前选中文本,目前只支持inline tag。tagName为标签名,attributes为该标签属性数组。
remove(tags):在当前选中文本中,清除指定的标签和属性。tags为你要删除的标签和属性。

http://kindeditor.net/demo.php

3.8.4、Kindeditor获取不了焦点的解决方法

使用layui弹出层时会发现kindeditor获取不了光标,这是因为多个层与iframe元素间叠放顺序的问题引起的,解决办法如下:

代码:

success: function(layero) {
layer.setTop(layero); //顶置
editor = KindEditor.create('#details',{
uploadJson : 'js/kindeditor4111/jsp/upload_json.jsp', //上传程序
fileManagerJson : 'js/kindeditor4111/jsp/file_manager_json.jsp', //文件管理
allowFileManager : true , //是否允许上传
/*
layui zIndex:19891014
KindEditor zIndex:811213
*/
zIndex:99999999 }); //创建一个富文本编辑器

要放在在窗体加载请求成功里面执行才有用,放外面没有用
第二次要移除KindEditor.remove("#details"); 

3.8.5、上传问题

富文本框,pageContext可能遇到上传目录不存在的问题

3.9、移动端UI框架

https://weui.io

http://www.jqweui.cn/

http://www.dcloud.io/mui.html

http://m.sui.taobao.org/

示例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>我的生活</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1" />
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" /> <link rel="stylesheet" href="js/suimobile/css/sm.min.css" />
<link rel="stylesheet" href="js/suimobile/css/sm-extend.min.css" /> </head>
<body> <div class="page-group">
<!-- 你的html代码 -->
<div class="page">
<header class="bar bar-nav">
<a class="button button-link button-nav pull-left" href="/demos/card">
<span class="icon icon-left"></span>
返回
</a>
<h1 class="title">我的生活</h1>
</header> <nav class="bar bar-tab">
<a class="tab-item external active" href="#">
<span class="icon icon-home"></span>
<span class="tab-label">首页</span>
</a>
<a class="tab-item external" href="#">
<span class="icon icon-me"></span>
<span class="tab-label">我</span>
</a>
<a class="tab-item external" href="#">
<span class="icon icon-star"></span>
<span class="tab-label">收藏</span>
</a>
<a class="tab-item external" href="#">
<span class="icon icon-settings"></span>
<span class="tab-label">设置</span>
</a>
</nav> <div class="content">
<!-- 这里是页面内容区 -->
<div class="page-index" id="list"> </div>
</div>
</div>
</div> <script type='text/javascript' src='js/suimobile/js/zepto.js' charset='utf-8'></script>
<script type='text/javascript' src='js/suimobile/js/sm.min.js' charset='utf-8'></script>
<script type='text/javascript' src='js/suimobile/js/sm-extend.min.js' charset='utf-8'></script>
<script>
$(function(){
$.init();
$.get("ProductController?action=getPager&limit=10&page=1",{},function(data){
$.each(data.data,function(index,obj){
c="<div class='card'>";
c+="<div style='background:url(\"images/"+obj.picture+"\") #fff center center' valign='bottom' class='card-header color-white no-border'>"+obj.name+"</div>";
c+="<div class='card-content'>";
c+="<div class='card-content-inner'>";
c+="<p class='color-gray'>发布日期 "+obj.addDate+"</p>";
c+="<p>此处是内容...</p>";
c+="</div>";
c+="</div>";
c+="<div class='card-footer'>";
c+="<a href='#' class='link'>赞</a>";
c+="<a href='#' class='link'>更多</a>";
c+="</div>";
c+="</div>";
$("#list").append(c);
});
});
});
</script>
</body>
</html>

运行结果:

如果需要演示可使用Total Control软件

四、素材、示例与视频

4.1、素材

链接: https://pan.baidu.com/s/1iFyQJ8oNWnoVrQ64rq2c6w 密码: 5a19

图标:http://www.fontawesome.com.cn/

layui文档:http://www.layui.com/doc

layui文档:http://www.layui.com/demo/

上传jar包:https://files.cnblogs.com/files/best/%E4%B8%8A%E4%BC%A0jar.zip

KindEditor下载:链接: https://pan.baidu.com/s/1IGBFVzMPjQ5FYCEKoYOc9w 密码: tv9v

GoMallPro项目:链接: https://pan.baidu.com/s/1wN2DRJXGoTgPv4rSnCSWlw 密码: 13tw (SUI)

LayUI后台管理与综合示例的相关教程结束。