首先,在包“com.example.demo”中新建一个“MybatisPlusConfig”类(在这个类中还可以对mybatis-plus进一步进行配置,本例中启用了分页插件),代码如下:
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
相关知识点:
(1)@EnableTransactionManagement注解
@EnableTransactionManagement 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactional 便可。
(2)@Configuration注解
@Configuration用于类,表明这个类是beans定义的源,可以定义bean。在 @Component 注解的类中不能定义类内依赖的@Bean注解的方法,而@Configuration可以。
(3)@Bean注解
用@Bean注解的方法:会实例化、配置并初始化一个新的对象,这个对象会由spring IoC 容器管理。
接着,在包“com.example.demo”中新建一个“WebConfig”类(用来映射用户上传的文件以及后面实现登录拦截器的设置),代码如下:
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
//图片存放根路径,从application.yml中读取upload
@Value("${upload}")
private String UPLOAD_PATH;
/**
* 文件上传
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//外部静态资源映射路径,用来上传文件
String filePath = "file:" + UPLOAD_PATH;
registry.addResourceHandler("/upload/**").addResourceLocations(filePath);
}
}
@Value("${upload}")表示从配置文件application.yml中读入配置信息,“upload”为配置的属性名称。registry.addResourceHandler("/upload/**"),把上传路径映射到“/upload/”的url路径中,可以通过url地址访问到文件。
在包“com.example.demo.model”中新建一个“User”类(如果自己添加model类时,只须定义好属性,然后利用eclipse的生成getter和setter功能,直接生成代码),代码如下:
package com.example.demo.model;
import java.sql.Timestamp;
/**
* 与数据库中的物理表映射,增删改一般都用这个模型实现
*/
import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
@TableName("t_sys_user")//数据库对应表名
public class User {
@TableId
private String id;//@TableId表示主键,与字段名称大小写一致
private String username;//与字段名称大小写一致
private String password;//与字段名称大小写一致
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Timestamp birthday;//与字段名称大小写一致
private String photo;//与字段名称大小写一致
private String introduce;//与字段名称大小写一致
private String usertype;//与字段名称大小写一致
public String getUsertype() {
return usertype;
}
public void setUsertype(String usertype) {
this.usertype = usertype;
}
public Timestamp getBirthday() {
return birthday;
}
public void setBirthday(Timestamp birthday) {
this.birthday = birthday;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getIntroduce() {
return introduce;
}
public void setIntroduce(String introduce) {
this.introduce = introduce;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
相关知识点:
(1)@TableName注解
Mybatis plus插件中的注解,指明model与数据库中关联的表名。
(2)@TableId注解
@TableId表示主键,与字段名称大小写一致。在设计表时字段名称建议不要使用大写字母,否则定义model属性时,生成getter和setter后看起来比较乱。
(3)@JsonFormat注解
@JsonFormat注解来源于jackson,Jackson是一个简单基于Java应用库,Jackson可以轻松的将Java对象转换成json对象和xml文档,同样也可以将json、xml转换成Java对象。
-
-
- 用户vo类
-
在包“com.example.demo.vo”中新建一个“UserVO”类(如果自己添加类时,只须定义好属性,然后利用eclipse的生成getter和setter功能,直接生成代码),代码如下:
package com.example.demo.vo;
import java.sql.Timestamp;
/**
* 展示模型(一般不做修改操作),不一定与物理表字段一致,可以是几张关联表的字段组合
* @author gjq
*
*/
public class UserVO{
private String id;
private String username;
private String password;
private Timestamp birthday;
private String photo;
private String introduce;
private String usertype;
// private String rolename;//关联角色表中的name字段,用来存放角色名
public String getUsertype() {
return usertype;
}
public void setUsertype(String usertype) {
this.usertype = usertype;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Timestamp getBirthday() {
return birthday;
}
public void setBirthday(Timestamp birthday) {
this.birthday = birthday;
}
public String getPhoto() {
return photo;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getIntroduce() {
return introduce;
}
public void setIntroduce(String introduce) {
this.introduce = introduce;
}
// public String getRolename() {
// return rolename;
// }
//
// public void setRolename(String rolename) {
// this.rolename = rolename;
// }
}
VO类与model类的区别:VO主要与前端展示结合使用,可以是多张表的组合数据,以显示功能为主;而model与表是一一对应的,model一般属性与表中的字段一致,实现表数据的增删改查功能,是更底层的数据模型。
-
-
- 用户mapper类以及xml文件
-
在包“com.example.demo.mapper”中新建一个“UserMapper”接口,代码如下:
package com.example.demo.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.baomidou.mybatisplus.plugins.pagination.Pagination;
import com.example.demo.model.User;
import com.example.demo.vo.UserVO;
@Mapper
public interface UserMapper extends BaseMapper<User>{
// Integer listCount();
// User findUserByUsername(String username);
List<UserVO> selectUserListPage(Pagination page ,UserVO userVO);
}
通过继承BaseMapper<User>,拥有了通用mapper的基本增删改查功能,因此用户表的基本增删改查功能不必再实现,这里定义的“selectUserListPage”是调用xml文件中的自定义查询,主要是可以实现多表连接查询和多条件查询(本例中较为简单,没有用到连接查询),扩展通用mapper没有的功能。
在“src/main/resources” 中的“mapper”文件夹中,新建一个文件,命名为“UserMapper.xml”,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 指明当前xml对应的Mapper -->
<mapper namespace="com.example.demo.mapper.UserMapper">
<!-- 多表查询,Select 的as后面的名称必须与UserVO属性名大小写一致 -->
<select id="selectUserListPage" parameterType="com.example.demo.vo.UserVO" resultType="com.example.demo.vo.UserVO">
SELECT
u.id as id,
u.username as username,
u.password as password,
u.birthday as birthday,
u.photo as photo,
u.usertype as usertype,
u.introduce as introduce
<!-- r.name as rolename -->
FROM
t_sys_user u
<!-- LEFT JOIN t_sys_role_user ru ON u.id = ru.sys_user_id
LEFT JOIN t_sys_role r ON ru.sys_role_id = r.id -->
WHERE 1=1
<if test="username != null">
and u.username like concat('%',#{username},'%')
</if>
<!-- <if test="rolename != null">
and r.name like concat('%',#{rolename},'%')
</if> -->
</select>
<!-- 以下为示例 -->
<!-- <select id="listCount" resultType="Integer">
SELECT COUNT(*) FROM t_sys_user;
</select>
<select id="findUserByUsername" parameterType="String" resultType="User">
SELECT * FROM t_sys_user WHERE username=#{username}
</select> -->
</mapper>
Xml文件采用mybatis语法格式来定义查询语句,namespace="com.example.demo.mapper.UserMapper"表示关联的mapper类,包名必须与自己源码中的包名一致,id="selectUserListPage"、parameterType="com.example.demo.vo.UserVO"、resultType="com.example.demo.vo.UserVO"分别与mapper中自定义的selectUserListPage函数名称、参数类型(Pagination是分页参数)、返回值类型一致,as语句后面的名称必须与返回值类型UserVO的属性名称大小写一致,test="username != null"中的“username”是参数类型UserVO中的属性名称,如果“username”值不为空,则按照该值进行模糊查询。其他查询语句的定义可以参考注释部分的代码,也可以访问官方网址:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html
在包“com.example.demo.service”中新建一个“UserService”类,代码如下:
package com.example.demo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.example.demo.mapper.UserMapper;
import com.example.demo.model.User;
import com.example.demo.util.Convert;
import com.example.demo.util.SnowflakeIdWorker;
import com.example.demo.vo.DataTableResult;
import com.example.demo.vo.UserVO;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;//注入mapper进行数据操作
/**
* 自定义xml形式的查询
* @return
*/
// public Integer listCount() {
//
// return userMapper.listCount();
//
// }
/**
* 自定义xml形式的查询
* @param username
* @return
*/
// public User findUserByUsername(String username) {
// return userMapper.findUserByUsername(username);
// }
//对于执行数据修改的方法加上事务处理
@Transactional
public int delete(String ids) {
//ids,逗号隔开的主键
List<String> listid=Convert.toListStrArray(ids);
return userMapper.deleteBatchIds(listid);
}
public User selectById(String id) {
//userMapper.selectOne(user),selectOne可以按照其他字段来查询一条记录
return userMapper.selectById(id);
}
public User selectByUser(User user) {
return userMapper.selectOne(user);
}
//对于执行数据修改的方法加上事务处理
@Transactional
public int updateById(User user) {
return userMapper.updateById(user);
}
//对于执行数据修改的方法加上事务处理
@Transactional
public int insert(User user) {
//添加雪花主键id
user.setId(SnowflakeIdWorker.getUUID());
int n = userMapper.insert(user);
//密码安全一点的话,不能原文保存,应该用MD5,也可以加盐处理
// n=1/0; //事务测试
return n;
}
/**
* 采用集成的查询方法
* @param username
* @return
*/
public List<User> selectList(String username) {
EntityWrapper<User> wrapper = new EntityWrapper<User>();
wrapper.like("username", username);
return userMapper.selectList(wrapper);
}
/**
* 分页查询
* @param user
* @return
*/
public DataTableResult selectUserListPage(UserVO userVO,int start,int length,String orderField,String orderDir) {
Page<UserVO> page = null;
//排序
if(!StringUtils.isEmpty(orderDir)&&!StringUtils.isEmpty(orderField)) {
if(orderDir.equals("asc")) {
page = new Page<>(start/length + 1, length,orderField,true);// 当前页,每页总条数 构造 page 对象
}else {
page = new Page<>(start/length + 1, length,orderField,false);// 当前页,每页总条数 构造 page 对象
}
}else {
page = new Page<>(start/length + 1, length,"id",false);//默认id降序
}
page.setRecords(userMapper.selectUserListPage(page, userVO));
DataTableResult result = new DataTableResult();
result.setRecordsTotal(page.getTotal());
result.setRecordsFiltered(page.getTotal());
result.setData(page.getRecords());
return result;
}
}
Service类实现业务层的代码,是最为复杂的部分,通过调用mapper类的方法实现对数据的增删改查操作,基本方法都比较固定,学会套用即可,类中用到的注解如下:
(1)@Service注解:如果一个类带了@Service注解,将自动注册到Spring容器,默认名称是类名(头字母小写),可以@Service(“xxxx”)这样来指定。
(2)@Autowired注解:@Autowired表示被修饰的类需要注入对象,spring会扫描所有被@Autowired标注的类,然后根据类型在ioc容器中找到匹配的类注入。
(3)@Transactional注解:@Transactional可以作用于接口、接口方法、类以及类方法上;当作用于类上时,该类的所有 public 方法将都具有该类型的事务属性,同时,我们也可以在方法级别使用该标注来覆盖类级别的定义。
在包“com.example.demo.controller”中新建一个“UserController”类,代码如下:
package com.example.demo.controller;
import java.io.File;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import com.example.demo.util.SnowflakeIdWorker;
import com.example.demo.vo.DataTableResult;
import com.example.demo.vo.Json;
import com.example.demo.vo.UserVO;
import com.google.code.kaptcha.Constants;
@Controller
@RequestMapping("/UserController")
public class UserController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private String prefix = "admin/user";// 页面的路径,注意admin前面不要有/
// 图片存放根路径,从application.yml中读取upload
@Value("${upload}")
private String UPLOAD_PATH;
@Autowired
private UserService userService;// 注入业务层的service
// 未加入@ResponseBody用来返回数据给页面
@RequestMapping("view")
public String view(Model model) {
return prefix + "/view";
}
// @ResponseBody,直接通过js异步返回数据给页面
@RequestMapping("list")
@ResponseBody
public DataTableResult list(HttpServletRequest request, UserVO userVO) {
// DataTableResult返回给datatables控件的数据格式
DataTableResult result = new DataTableResult();
// 获取分页参数
int start = Integer.parseInt(request.getParameter("start"));
int length = Integer.parseInt(request.getParameter("length"));
// 获取排序字段
String orderIdx = request.getParameter("order[0][column]");
// 获取排序字段名
String orderField = request.getParameter("columns[" + orderIdx + "][name]");
// 获取排序方式,降序desc或者升序asc
String orderDir = request.getParameter("order[0][dir]");
// 调用分页查询方法
result = userService.selectUserListPage(userVO, start, length, orderField, orderDir);
// result.setDraw(userVO.getDraw());
return result;
}
// @ResponseBody,直接通过js异步返回数据给页面
@RequestMapping("insert")
@ResponseBody
public Json insert(User user) {
Json j = new Json();
if (userService.insert(user) > 0) {
j.setSuccess(true);
j.setMsg("添加成功!");
} else {
j.setSuccess(false);
j.setMsg("添加失败!");
}
return j;
}
// @ResponseBody,直接通过js异步返回数据给页面
@RequestMapping("update")
@ResponseBody
public Json updateById(User user) {
Json j = new Json();
if (userService.updateById(user) > 0) {
j.setSuccess(true);
j.setMsg("修改成功!");
} else {
j.setSuccess(false);
j.setMsg("修改失败!");
}
return j;
}
// @ResponseBody,直接通过js异步返回数据给页面
@RequestMapping("select")
@ResponseBody
public Json selectById(User user) {
Json j = new Json();
j.setSuccess(true);
j.setObj(userService.selectById(user.getId()));
return j;
}
// @ResponseBody,直接通过js异步返回数据给页面
@RequestMapping("delete")
@ResponseBody
public Json delete(HttpServletRequest request) {
Json j = new Json();
String ids = request.getParameter("ids");
if (!StringUtils.isEmpty(ids)) {
j.setSuccess(true);
j.setObj("成功删除" + userService.delete(ids) + "条记录");
} else {
j.setSuccess(false);
j.setMsg("没有需要删除的记录!");
}
return j;
}
// @ResponseBody,直接通过js异步返回数据给页面
// @RequestParam("file[]") MultipartFile[] file 多个文件
@RequestMapping("upload")
@ResponseBody
public Json upload(HttpServletRequest request, @RequestParam("file") MultipartFile file) {
Json j = new Json();
if (!file.isEmpty()) {
try {
String originalFilename = file.getOriginalFilename();
// 随机文件名
String newFileName = SnowflakeIdWorker.getUUID()
+ originalFilename.substring(originalFilename.lastIndexOf("."));
// 上传文件路径
File upload = new File(UPLOAD_PATH, "images/");
if (!upload.exists())
upload.mkdirs();
String uploadPath = upload + "\\";
logger.info("uploadPath = " + uploadPath);
File uploadfile = new File(uploadPath + newFileName);
// 将上传文件保存到一个目标文件当中
file.transferTo(uploadfile);
j.setSuccess(true);
j.setObj("/upload/images/" + newFileName);
} catch (IllegalStateException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
j.setSuccess(false);
j.setObj("上传异常");
}
} else {
j.setSuccess(false);
j.setObj("上传失败");
}
return j;
}
}
Controller类负责数据的传入与传出,可以做一些数据校验,但尽量不涉及底层的数据库操作,应该交给service来实现,相关知识点如下:
(1)@Controller用于标记在一个类上,使用它标记的类就是一个SpringMVC Controller 对象。
(2)@RequestMapping是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。
(3)@ResponseBody这个注解通常使用在控制层(controller)的方法上,其作用是将方法的返回值以特定的格式写入到response的body区域,进而将数据返回给客户端,例如JSON数据,常用在AJAX中的异步请求调用。当方法上面没有写ResponseBody,底层会将方法的返回值封装为ModelAndView对象,返回页面地址。
(4)@Value("${upload}")表示从配置文件application.yml中读入配置信息,“upload”为配置的属性名称。
(5)logger用来打印日志,在控制台或者logs文件夹下面的日志文件中显示信息,常用来调试和跟踪变量的值,要学会使用,例如logger.info()方法等。
(6)方法中如何获取页面传递过来的参数:一种是通过定义HttpServletRequest参数request,来获取参数,该方法可以获取各种参数,但是需要自己一一获取,常用在一些特殊参数值的获取;另一种是通过对象,如User类型参数user,如果参数名与类中的属性名大小写相同,则直接自动赋值,该方法比较常用。
(7)返回值:一种是String类型,一般是用来返回页面地址;另一种是对象类型,如Json,是自定义的数据类型,用来封装异步返回的数据。
(8)文件上传:利用了MultipartFile类型的参数file获取文件对象,通过file.transferTo()方法保存到配置文件的上传路径中
简单测试一下接口:
(1)运行项目
(2)测试
打开浏览器,建议用chrome或者360浏览器的极速模式,输入地址http://127.0.0.1:8080/UserController/select?id=1,看到数据就表示访问成功:
转存失败重新上传取消正在上传…重新上传取消正在上传…重新上传取消正在上传…重新上传取消正在上传…重新上传取消正在上传…重新上传取消
后台管理界面采用了开源项目“hAdmin”,GitHub地址:https://github.com/huangyaoxin/hAdmin。hAdmin是一个免费的后台管理模版,该模版基于bootstrap(https://v3.bootcss.com/components/)与jQuery(https://www.runoob.com/jquery/jquery-tutorial.html)制作,集成了众多常用插件。
Spring Boot 中推荐使用Thymeleaf作为模板引擎,因为 Thymeleaf 提供了完美的 Spring MVC支持。Thymeleaf是一个跟 Velocity、FreeMarker类似的模板引擎,它可以完全替代JSP。官方的使用教程地址:https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html。中文版教程:https://www.e-learn.cn/thymeleaf。
后台页面采用bootstrap与jQuery框架,结合Thymeleaf模板引擎实现,模板文件为带Thymeleaf标签的html文件,统一放在templates文件夹里面。
在templates文件夹新建一个文件夹“admin”,因为controller的转发路径都以admin开头。
添加主界面文件,在“admin”文件夹-> 右键->new->file,输入“index.html”,代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="renderer" content="webkit">
<title> hAdmin- 主页</title>
<meta name="keywords" content="">
<meta name="description" content="">
<!--[if lt IE 9]>
<meta http-equiv="refresh" content="0;ie.html" />
<![endif]-->
<link rel="shortcut icon" href="favicon.ico">
<link th:href="@{/static/css/bootstrap.min.css?v=3.3.6}" rel="stylesheet">
<link th:href="@{/static/css/font-awesome.min.css?v=4.4.0}" rel="stylesheet">
<link th:href="@{/static/css/animate.css}" rel="stylesheet">
<link th:href="@{/static/css/style.css?v=4.1.0}" rel="stylesheet">
</head>
<body class="fixed-sidebar full-height-layout gray-bg" style="overflow:hidden">
<div id="wrapper">
<!--左侧导航开始-->
<nav class="navbar-default navbar-static-side" role="navigation">
<div class="nav-close"><i class="fa fa-times-circle"></i>
</div>
<div class="sidebar-collapse">
<ul class="nav" id="side-menu">
<li class="nav-header">
<div class="dropdown profile-element">
<a data-toggle="dropdown" class="dropdown-toggle" href="#">
<span class="clear">
<span class="block m-t-xs" style="font-size:20px;">
<i class="fa fa-bank"></i>
<strong class="font-bold">管理系统</strong>
</span>
</span>
</a>
</div>
<div class="logo-element">管理系统
</div>
</li>
<li>
<a class="J_menuItem" href="/home">
<i class="fa fa-home"></i>
<span class="nav-label">主页</span>
</a>
</li>
<li>
<a href="#">
<i class="fa fa-desktop"></i>
<span class="nav-label">系统设置</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li>
<a class="J_menuItem" href="/UserController/view">用户管理</a>
</li>
<li>
<a class="J_menuItem" href="/PermissionController/view">权限管理</a>
</li>
<li>
<a class="J_menuItem" href="/RoleController/view">角色管理</a>
</li>
</ul>
</li>
<li>
<a href="#">
<i class="fa fa-file-o"></i>
<span class="nav-label">测试分类</span>
<span class="fa arrow"></span>
</a>
<ul class="nav nav-second-level">
<li>
<a class="J_menuItem" href="graph_echarts.html">测试页面</a>
</li>
</ul>
</li>
</ul>
</div>
</nav>
<!--左侧导航结束-->
<!--右侧部分开始-->
<div id="page-wrapper" class="gray-bg dashbard-1">
<div class="row border-bottom">
<nav class="navbar navbar-static-top" role="navigation" style="margin-bottom: 0">
<div class="navbar-header"><a class="navbar-minimalize minimalize-styl-2 btn btn-info " href="#"><i class="fa fa-bars"></i> </a>
<form role="search" class="navbar-form-custom" method="post" action="search_results.html">
<div class="form-group">
<input type="text" placeholder="请输入您需要查找的内容 …" class="form-control" name="top-search" id="top-search">
</div>
</form>
</div>
<ul class="nav navbar-top-links navbar-right">
<li>
<span th:text="${username}"></span><span><a href="/UserController/logout">注销</a></span>
</li>
<li class="dropdown">
<a class="dropdown-toggle count-info" data-toggle="dropdown" href="#">
<i class="fa fa-envelope"></i> <span class="label label-warning">16</span>
</a>
<ul class="dropdown-menu dropdown-messages">
<li class="m-t-xs">
<div class="dropdown-messages-box">
<a href="profile.html" class="pull-left">
<img alt="image" class="img-circle" th:src="@{/static/img/a7.jpg}">
</a>
<div class="media-body">
<small class="pull-right">46小时前</small>
<strong>小四</strong> 是不是只有我死了,你们才不骂爵迹
<br>
<small class="text-muted">3天前 2014.11.8</small>
</div>
</div>
</li>
<li class="divider"></li>
<li>
<div class="dropdown-messages-box">
<a href="profile.html" class="pull-left">
<img alt="image" class="img-circle" th:src="@{/static/img/a4.jpg}">
</a>
<div class="media-body ">
<small class="pull-right text-navy">25小时前</small>
<strong>二愣子</strong> 呵呵
<br>
<small class="text-muted">昨天</small>
</div>
</div>
</li>
<li class="divider"></li>
<li>
<div class="text-center link-block">
<a class="J_menuItem" href="mailbox.html">
<i class="fa fa-envelope"></i> <strong> 查看所有消息</strong>
</a>
</div>
</li>
</ul>
</li>
<li class="dropdown">
<a class="dropdown-toggle count-info" data-toggle="dropdown" href="#">
<i class="fa fa-bell"></i> <span class="label label-primary">8</span>
</a>
<ul class="dropdown-menu dropdown-alerts">
<li>
<a href="mailbox.html">
<div>
<i class="fa fa-envelope fa-fw"></i> 您有16条未读消息
<span class="pull-right text-muted small">4分钟前</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<a href="profile.html">
<div>
<i class="fa fa-qq fa-fw"></i> 3条新回复
<span class="pull-right text-muted small">12分钟钱</span>
</div>
</a>
</li>
<li class="divider"></li>
<li>
<div class="text-center link-block">
<a class="J_menuItem" href="notifications.html">
<strong>查看所有 </strong>
<i class="fa fa-angle-right"></i>
</a>
</div>
</li>
</ul>
</li>
</ul>
</nav>
</div>
<div class="row J_mainContent" id="content-main">
<iframe id="J_iframe" width="100%" height="100%" src="/home" frameborder="0" data-id="/home" seamless></iframe>
</div>
</div>
<!--右侧部分结束-->
</div>
<!-- 全局js -->
<script th:src="@{/static/js/jquery.min.js?v=2.1.4}"></script>
<script th:src="@{/static/js/bootstrap.min.js?v=3.3.6}"></script>
<script th:src="@{/static/js/plugins/metisMenu/jquery.metisMenu.js}"></script>
<script th:src="@{/static/js/plugins/slimscroll/jquery.slimscroll.min.js}"></script>
<script th:src="@{/static/js/plugins/layer/layer.min.js}"></script>
<!-- 自定义js -->
<script th:src="@{/static/js/hAdmin.js?v=4.1.0}"></script>
<script type="text/javascript" th:src="@{/static/js/index.js}"></script>
<!-- 第三方插件 -->
<script th:src="@{/static/js/plugins/pace/pace.min.js}"></script>
</body>
</html>
在html标签中需要加入“<html xmlns:th="http://www.thymeleaf.org">”表示是Thymeleaf模板文件,在页面中以“th:”开头的也都是Thymeleaf标签,本项目中只是简单用了一些标签,大部分效果还是通过jquery来控制。
添加首页文件,在“admin”文件夹-> 右键->new->file,输入“home.html”,代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="renderer" content="webkit">
<title>主页</title>
<meta name="keywords" content="">
<meta name="description" content="">
<!--[if lt IE 9]>
<meta http-equiv="refresh" content="0;ie.html" />
<![endif]-->
<link rel="shortcut icon" href="favicon.ico">
<link th:href="@{/static/css/bootstrap.min.css?v=3.3.6}" rel="stylesheet">
<link th:href="@{/static/css/font-awesome.min.css?v=4.4.0}" rel="stylesheet">
<link th:href="@{/static/css/animate.css}" rel="stylesheet">
<link th:href="@{/static/css/style.css?v=4.1.0}" rel="stylesheet">
</head>
<body class="gray-bg">
<div class="row wrapper border-bottom white-bg page-heading">
<div class="col-sm-4">
<h2>主页</h2>
</div>
</div>
<div class="wrapper wrapper-content">
<div class="row">
<div class="col-sm-12">
<div class="middle-box text-center animated fadeInRightBig">
<h3 class="font-bold">这里是主页</h3>
</div>
</div>
</div>
</div>
<!-- 全局js -->
<script th:src="@{/static/js/jquery.min.js?v=2.1.4}"></script>
<script th:src="@{/static/js/bootstrap.min.js?v=3.3.6}"></script>
<script th:src="@{/static/js/plugins/layer/layer.min.js}"></script>
<!-- 自定义js -->
<script th:src="@{/static/js/content.js}"></script>
</body>
</html>
Home页面以iframe形式嵌入到index.html页面中。
模板文件不能直接访问,必须通过后台转发,因此在包“com.example.demo.controller”中新建一个“HomeController”类来转发上面的地址,代码如下:
package com.example.demo.controller;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HomeController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
// 未加入@ResponseBody用来返回数据给页面
@RequestMapping("/index")
public String index(HttpServletRequest request,Model model) {
return "admin/index";
}
// 未加入@ResponseBody用来返回数据给页面
@RequestMapping("/home")
public String home(Model model) {
return "admin/home";
}
}
确保项目在运行中,如果停止了,通过 启动,打开浏览器,输入地址:http://127.0.0.1:8080/index,可以看到以下效果:
url地址中的index是@RequestMapping("/index")映射的地址,会按照返回值转化为templates路径中的“admin/index.html”,扩展名可以省略。
添加用户管理界面,在“admin”文件夹中新建一个文件夹“user”,在“user”文件夹-> 右键->new->file,输入“view.html”(这里的路径主要是由controller的转发方法决定,保持一致即可),代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="renderer" content="webkit">
<title>用户管理</title>
<meta name="keywords" content="">
<meta name="description" content="">
<!--[if lt IE 9]>
<meta http-equiv="refresh" content="0;ie.html" />
<![endif]-->
<link rel="shortcut icon" href="favicon.ico">
<link th:href="@{/static/css/bootstrap.min.css?v=3.3.6}"
rel="stylesheet">
<link th:href="@{/static/css/font-awesome.min.css?v=4.4.0}"
rel="stylesheet">
<link th:href="@{/static/css/animate.css}" rel="stylesheet">
<link th:href="@{/static/css/style.css?v=4.1.0}" rel="stylesheet">
<!-- Data Tables -->
<link
th:href="@{/static/css/plugins/dataTables/dataTables.bootstrap.css}"
rel="stylesheet">
<!-- Ztree -->
<link rel="stylesheet" th:href="@{/static/css/plugins/ztree/zTreeStyle/zTreeStyle.css}" type="text/css">
<!-- toastr -->
<link th:href="@{/static/css/plugins/toastr/toastr.min.css}" rel="stylesheet">
<!-- summernote -->
<link th:href="@{/static/css/plugins/summernote/summernote.css}" rel="stylesheet">
<link th:href="@{/static/css/plugins/summernote/summernote-bs3.css}" rel="stylesheet">
<!-- dropzone -->
<link th:href="@{/static/css/plugins/dropzone/basic.css}" rel="stylesheet">
<link th:href="@{/static/css/plugins/dropzone/dropzone.css}" rel="stylesheet">
</head>
<body class="gray-bg">
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>用户管理</h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="table_data_tables.html#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="table_data_tables.html#">选项1</a>
</li>
<li><a href="table_data_tables.html#">选项2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="form-horizontal">
<div class="form-group">
<div class="col-sm-4">
<button id="btn_add" class="btn btn-primary btn-sm" ><i class="fa fa-plus"></i> 添加</button>
<button id="btn_del" class="btn btn-danger btn-sm m-l-sm" ><i class="fa fa-remove"></i> 删除</button>
<button id="btn_export" class="btn btn-primary btn-sm m-l-sm" onclick="$('#table').tableExport({type:'excel',escape:'false',tableName:'导出表格',ignoreColumn:[0,4]});"><i class="fa fa-file-excel-o"></i> 导出</button>
</div>
<label class="col-sm-1 control-label">搜索:</label>
<div class="col-sm-2">
<select id="searchfield" class="form-control">
<!-- value为查找字段名称 -->
<option value="username">用户名</option>
</select>
</div>
<div class="col-sm-3">
<input id="keyword" type="search" class="form-control" placeholder="关键字" />
</div>
<div class="col-sm-2">
<button id="btn_search" class="btn btn-primary btn-sm m-l-sm" ><i class="fa fa-search"></i> 搜索</button>
</div>
</div>
</div>
<table class="table table-striped table-bordered table-hover" id="table">
<thead>
<tr>
<th style="padding-left: 10px;">
<input type="checkbox" id="cb_selectAll" class="input-lg" style="width:20px;height:20px;"/>
</th>
<th>id</th>
<th>用户名</th>
<th>用户类型</th>
<th>操作</th>
</tr>
</thead>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- 模态窗口 -->
<div class="modal fade" data-backdrop="static" id="modal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span><span class="sr-only">Close</span>
</button>
<h2 class="modal-title" id="modaltitle"></h2>
</div>
<div class="modal-body">
<div class="row">
<!-- 表单布局 -->
<form id="form">
<div class="col-md-12">
<div class="form-group">
<label class="col-sm-3 control-label"><font color="#FF0000">*</font>用户名称:</label>
<div class="col-sm-9">
<!-- 保存修改的主键值 -->
<input type="hidden" name="id" id="id">
<input class="form-control" type="text" name="username" id="username"
placeholder="请输入用户名" >
<span class="help-block m-b-none"></span>
</div>
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label class="col-sm-3 control-label"><font color="#FF0000">*</font>用户密码:</label>
<div class="col-sm-3">
<input class="form-control" type="password" name="password" id="password"
placeholder="请输入用户密码" >
<span class="help-block m-b-none"></span>
</div>
<label class="col-sm-3 control-label"><font color="#FF0000">*</font>确认密码:</label>
<div class="col-sm-3">
<input class="form-control" type="password" name="repassword" id="repassword"
placeholder="确认密码" >
<span class="help-block m-b-none"></span>
</div>
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label class="col-sm-3 control-label">用户类型:</label>
<div class="col-sm-9">
<select id="usertype" class="form-control">
<option value="普通用户">普通用户</option>
<option value="超级管理员">超级管理员</option>
</select>
<span class="help-block m-b-none"></span>
</div>
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label class="col-sm-3 control-label">出生日期:</label>
<div class="col-sm-9">
<input class="form-control layer-date" name="birthday" id="birthday" placeholder="YYYY-MM-DD hh:mm:ss" onclick="laydate({istime: true, format: 'YYYY-MM-DD hh:mm:ss'})">
<label class="laydate-icon"></label>
<span class="help-block m-b-none"></span>
</div>
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label class="col-sm-3 control-label">头像:</label>
<div class="col-sm-9">
<img alt="image" id="photo" style="width: 150px; height: 150px;" class="img-circle" th:src="@{/static/img/a7.jpg}">
</div>
</div>
</div>
<div class="col-md-12">
<div id="fileupload" class="dropzone">
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<label class="col-sm-3 control-label">个人简介:</label>
<div class="col-sm-9">
<div class="summernote" id="introduce">
</div>
<span class="help-block m-b-none"></span>
</div>
</div>
</div>
</form>
<!-- 表单布局结束 -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white"
data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="btn_save">保存</button>
</div>
</div>
</div>
</div>
<!-- 模态窗口结束 -->
<!-- 分配角色模态窗口 -->
<div class="modal fade" data-backdrop="static" id="rolemodal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span><span class="sr-only">Close</span>
</button>
<h2 class="modal-title" id="rolemodaltitle">分配角色</h2>
</div>
<div class="modal-body">
<div class="row">
<!-- 表单布局 -->
<form id="roleform">
<div class="col-md-12">
<!-- 保存修改的主键值 -->
<input type="hidden" name="userid" id="userid">
<ul id="tree" class="ztree"></ul>
</div>
</form>
<!-- 表单布局结束 -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white"
data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="btn_rolesave">保存</button>
</div>
</div>
</div>
</div>
<!-- 模态窗口结束 -->
<!-- 全局js -->
<script th:src="@{/static/js/jquery.min.js?v=2.1.4}"></script>
<script th:src="@{/static/js/bootstrap.min.js?v=3.3.6}"></script>
<script th:src="@{/static/js/plugins/layer/layer.min.js}"></script>
<!-- 自定义js -->
<script th:src="@{/static/js/content.js}"></script>
<!-- Data Tables -->
<script th:src="@{/static/js/plugins/dataTables/jquery.dataTables.js}"></script>
<script
th:src="@{/static/js/plugins/dataTables/dataTables.bootstrap.js}"></script>
<!-- tableexport -->
<!-- 前端直接导出excel有一定的缺陷,使用后台导出功能更强大
后台导出:阿里巴巴项目组提供了easyexcel工具类,github地址:https://github.com/alibaba/easyexcel -->
<script th:src="@{/static/js/plugins/tableexport/tableExport.js}"></script>
<script th:src="@{/static/js/plugins/tableexport/jquery.base64.js}"></script>
<!-- ztree -->
<script th:src="@{/static/js/plugins/ztree/jquery.ztree.core.min.js}"></script>
<script th:src="@{/static/js/plugins/ztree/jquery.ztree.excheck.min.js}"></script>
<!-- Toastr script -->
<script th:src="@{/static/js/plugins/toastr/toastr.min.js}"></script>
<!-- jQuery Validation plugin javascript-->
<script th:src="@{/static/js/plugins/validate/jquery.validate.min.js}"></script>
<script th:src="@{/static/js/plugins/validate/messages_zh.min.js}"></script>
<!-- layerDate plugin javascript -->
<script th:src="@{/static/js/plugins/layer/laydate/laydate.js}"></script>
<!-- SUMMERNOTE -->
<script th:src="@{/static/js/plugins/summernote/summernote.min.js}"></script>
<script th:src="@{/static/js/plugins/summernote/summernote-zh-CN.js}"></script>
<!-- DROPZONE -->
<script th:src="@{/static/js/plugins/dropzone/dropzone.js}"></script>
<!-- Page-Level Scripts -->
<script>
//表格行中的按钮点击事件
function edit(id){
//异步获取数据
$.ajax({
type: "get",
data: {
id:id,//第一个id为参数名,第二个为参数值
},
url: "/UserController/select",//后台处理地址
success: function (data) {
//console.log(data);
if(data.success){
//设置数据
$("#id").val(data.obj.id);//修改数据必须有主键值
$("#username").val(data.obj.username);
$("#password").val(data.obj.password);
$("#repassword").val(data.obj.password);
$("#usertype").val(data.obj.usertype);
$("#birthday").val(data.obj.birthday);
$('#photo').attr("src",data.obj.photo);
$('#introduce').summernote("code", data.obj.introduce);
$("#modaltitle").text("修改用户");
$("#modal").modal("show");
}else{
toastr.error(data.msg, '错误!');
}
}
}); // end ajax
}//end edit
//表格行中的按钮点击事件
function role(id){
//异步获取数据
$.ajax({
type: "get",
data: {
id:id,//第一个id为参数名,第二个为参数值
},
url: "/RoleController/tree",//后台处理地址
success: function (data) {
//ztree
var setting = {
check: {
enable: true
},
data: {
simpleData: {
enable: true
}
}
};
$.fn.zTree.init($("#tree"), setting, data);
$("#userid").val(id);//通过隐藏input保存用户id
$("#rolemodal").modal("show");
}
}); // end ajax
}
$(document).ready(function () {
//datatable
var datatable= $('#table').DataTable({
"processing": true,
"serverSide": true,
"ajax": {
url: "/UserController/list",
type:"post",
data: function (d) {
//把字段名和关键词发送给controller进行查询,自动映射到vo模型的相应属性中
d[$('#searchfield').val()]=$('#keyword').val()
}
},
"language": {
"lengthMenu": "每页 _MENU_ 行",
"info": "从 _START_ 到 _END_,共 _TOTAL_ 记录",
"zeroRecords": "没有找到记录",
"infoEmpty": "暂无记录",
"infoFiltered": "(从 _MAX_ 条记录过滤)",
"paginate": {
"previous": "上一页",
"next": "下一页",
},
"processing": "正在加载..."
},
"autoWidth": false,
"pageLength": 2,
"lengthChange": false,
"searching": false,
"columns": [
{"data":"id","orderable": false,
"render": function ( data, type, full, meta ) {
return '<input type="checkbox" value="'+data+'" class="input-lg" style="width:20px;height:20px;" />';
}
},
{"data":"id","name":"id"},
{"data":"username","name":"username"},
{"data":"usertype","name":"usertype"},
//有排序功能必须指定name为字段名称
{"data":"id","orderable": false,
"render": function ( data, type, full, meta ) {
return '<button id="btn_edit" class="btn btn-primary btn-sm" οnclick="edit(\''+data+'\')"><i class="fa fa-edit"></i> 查看修改</button> <button id="btn_role" class="btn btn-primary btn-sm" οnclick="role(\''+data+'\')"><i class="fa fa-users"></i> 分配角色</button>';
}
},
],
"order": [
[1, 'desc']
]//默认排序
});
$("#btn_search").click(function(){
datatable.ajax.reload();//根据关键词重新加载数据
});
//全选
$("#cb_selectAll").click(function(){
if ($("#cb_selectAll").get(0).checked) {
$("#table tbody :checkbox").prop("checked", true);
}else{
$("#table tbody :checkbox").prop("checked", false);
}
});
//toastr选项
toastr.options = {
"positionClass": "toast-bottom-center",
}
//删除
$("#btn_del").click(function(){
//获取选中的复选框
var checkboxlist=$("#table tbody :checked");
if(checkboxlist.length>0){
if(!confirm("您确定删除数据吗?"))
{
return;
}
}else{
toastr.error("请选择要删除的记录。", '错误!');
return;
}
var ids="";
$.each(checkboxlist, function(n, cb) {
ids+=cb.value+",";
});
if(ids.length>0){
ids=ids.substring(0,ids.length-1);
}
//异步删除数据
$.ajax({
type: "post",
data: {
ids:ids,//第一个ids为参数名,第二个为参数值
},
url: "/UserController/delete",//后台处理地址
success: function (data) {
if(data.success){
toastr.success(data.msg, '删除成功!');
datatable.ajax.reload(null, false);//刷新当前页
}else{
toastr.error(data.msg, '错误!');
}
}
}); // end ajax
});//end btn_del
$("#btn_add").click(function(){
//清空数据
$("#username").val("");
$("#password").val("");
$("#repassword").val("");
$("#usertype").val("普通用户");
$("#birthday").val("");
$('#photo').attr("src","");
$('#introduce').summernote("code", "");
//validator.resetForm();//重置验证
$("#modaltitle").text("添加用户");
$("#modal").modal("show");
});//end add
//不用改,以下为修改jQuery Validation插件兼容Bootstrap的方法,没有直接写在插件中是为了便于插件升级
$.validator.setDefaults({
highlight: function (element) {
$(element).closest('.form-group').removeClass('has-success').addClass('has-error');
},
success: function (element) {
element.closest('.form-group').removeClass('has-error').addClass('has-success');
},
errorElement: "span",
errorPlacement: function (error, element) {
if (element.is(":radio") || element.is(":checkbox")) {
error.appendTo(element.parent().parent().parent());
} else {
error.appendTo(element.parent());
}
},
errorClass: "help-block m-b-none",
validClass: "help-block m-b-none"
});
//end setDefaults
// validate form setting
var icon = "<i class='fa fa-times-circle'></i> ";
validator=$("#form").validate({
rules: {
username: {
required: true,
minlength: 1
},
password: {
required: true,
minlength: 1
},
repassword: {
required: true,
minlength: 1,
equalTo: "#password"
},
},
messages: {
username: {
required: icon + "请输入您的用户名",
minlength: icon + "用户名必须1个字符以上"
},
password: {
required: icon + "请输入您的密码",
minlength: icon + "密码必须1个字符以上"
},
repassword: {
required: icon + "请再次输入密码",
minlength: icon + "密码必须1个字符以上",
equalTo: icon + "两次输入的密码不一致"
},
}
});//end validate
$("#btn_save").click(function(){
if($("#form").valid()){
//save
var markupStr = $('#introduce').summernote('code');
//alert(markupStr);
if($("#modaltitle").text()=="添加用户"){
//add
//异步添加数据
$.ajax({
type: "post",
data: {
username:$("#username").val(),
password:$("#password").val(),
usertype:$("#usertype").val(),
birthday:$("#birthday").val(),
photo:$('#photo').attr("src"),
introduce:$('#introduce').summernote("code"),
},
url: "/UserController/insert",//后台处理地址
success: function (data) {
if(data.success){
toastr.success(data.msg, '添加成功!');
$("#modal").modal('hide');
datatable.ajax.reload(null, false);//刷新当前页
}else{
toastr.error(data.msg, '错误!');
}
}
}); // end ajax
}else{
//update
//异步修改数据
$.ajax({
type: "post",
data: {
id:$("#id").val(),//主键,从隐藏input获取到
username:$("#username").val(),
password:$("#password").val(),
usertype:$("#usertype").val(),
birthday:$("#birthday").val(),
photo:$('#photo').attr("src"),
introduce:$('#introduce').summernote("code"),
},
url: "/UserController/update",//后台处理地址
success: function (data) {
if(data.success){
toastr.success(data.msg, '修改成功!');
$("#modal").modal('hide');
datatable.ajax.reload(null, false);//刷新当前页
}else{
toastr.error(data.msg, '错误!');
}
}
}); // end ajax
}
}
});//end btn_save
//summernote
$('#introduce').summernote({
lang: 'zh-CN'
});
//Dropzone
Dropzone.autoDiscover = false;// 禁止对所有元素的自动查找,由于Dropzone会自动查找class为dropzone的元素
var myDropzone = new Dropzone("#fileupload", {
url: "/UserController/upload",
method:"post", //也可用put
paramName:"file", //后台接收文件参数名称,默认为file
maxFiles:1,//一次性上传的文件数量上限
maxFilesize: 2, //文件大小,单位:MB
acceptedFiles: ".jpg,.gif,.png,.jpeg", //上传的类型
addRemoveLinks: true,
dictRemoveFile: "删除",
dictCancelUpload: "取消",
dictMaxFilesExceeded: "最多上传一个文件",
dictFallbackMessage: '不好意思,您的浏览器不支持!',//如果浏览器不支持,默认消息将被替换为这个文本。默认为 “Your browser does not support drag'n'drop file uploads.”。
dictInvalidFileType: '该文件不允许上传',//如果文件类型不匹配时显示的错误消息。
dictResponseError:'上传失败,请稍后重试',//如果服务器响应是无效的时候显示的错误消息。
autoProcessQueue: true,
//uploadMultiple:true,//允许多个文件上传
clickable: true,
init:function(){
this.on("addedfile", function(file) {
//上传文件时触发的事件
console.log("addedfile");
});
this.on("success",function(file,data){
//上传成功触发的事件
console.log("success");
console.log(data);
if(data.success){
$('#photo').attr("src", data.obj);
toastr.success("上传头像成功!", '成功');
myDropzone.removeFile(file);//上传界面的预览删除
}
});
this.on("error",function (file,data) {
//上传失败触发的事件
console.log("error");
});
this.on("removedfile",function(file){
//删除文件时触发的方法
console.log("removedfile");
});
},
});// end Dropzone
$("#btn_rolesave").click(function(){
var treeObj = $.fn.zTree.getZTreeObj("tree");
var nodes = treeObj.getCheckedNodes(true);
ids="";
for(i=0;i<nodes.length;i++){
if(i<nodes.length - 1){
ids = ids + nodes[i].id + ",";
}else{
ids = ids + nodes[i].id;
}
}
//console.log(ids);
$.ajax({
type: "post",
data: {
id:$("#userid").val(),
ids:ids
},
url: "/RoleController/role",//后台处理地址
success: function (data) {
if(data.success){
toastr.success("分配角色成功!", '成功');
$("#rolemodal").modal("hide");
}
}
}); // end ajax
});//end rolesave
});//end ready
</script>
</body>
</html>
数据的增删改查都通过$.ajax以json格式异步发送到controller中进行处理。本页面中还封装了表格、表单验证、在线编辑器、文件上传组件、树形组件(需要调用到角色表,等角色模块完成就可以正常使用)等扩展组件,注意阅读代码中的注释,代码基本以块形式出现,每个扩展都在相应的代码段中。因为涉及的组件较多,重点学会3步套用法即可(1、引入css;2、引入js;3、编写事件处理代码)。异步调用时,一定要学会用console.log()来打印数据进行调试与后台中的logger.info()方法类似。
点击用户管理菜单的效果(除了分配角色功能,其他的都已经实现):