1. 登录
业务逻辑:
管理者登录 (roles)
系统管理员登录(admin)
jquery 开始函数
$(function(){})
导入静态页面:
原本路径
原本路径
../static/CSS/left.css
实际导入路径
../CSS/left.css
idea 多选:ctrl + shift + alt
=======================================================================================================
2.服务管理
-
销售经理 : 创建服务、处理服务、反馈服务、查看服务归档
-
销售主管:分配服务、查看服务归档

指派人:销售主管指派客户经理
服务管理业务流程:
客户经理创建服务, 销售主管分配服务(唯一),客户经理接受指派的服务,处理服务,反馈服务(只有处理完的服务才能进行反馈==>上门反馈,电话反馈 ),最后归档
=======================================================================================================
3.数据库说明
数据库说明:CustomServices表,字段 : CSState
| 1=新创建 | |
|---|---|
| 2=已分配 | |
| 3=已处理 | |
| 4=已归档 |
数据库: 角色ID --> 相当于角色的身份,如系统管理员,销售主管
users表中角色表字段说明: (roleID字段)
| 0 | 系统管理员身份 |
|---|---|
| 1 | 销售主管 |
| 2 | 客户经理 |
- 管理员可以进用户界面也可以进管理员界面,用户只能 进用户界面
字段说明:
| userlname | 登录名 (必须唯一) |
|---|---|
| username | 真实姓名 |
权限的第三个表只是给开发人员看的,角色要行驶什么权限,只要在Ctroller中添加注解,表示什么角色能够操作 (好像也不对)
=======================================================================================================
4.查漏补缺(问题记录)
1.layui的使用
监听表单事件
$('.layui-form').on('submit',function(data){
alert(1)
})
2.存一个session后台所有页面都能拿到吗?
答案: 全局可以拿到session的值,thymleaf中,使用文本拿值,用的是text而不是test
3.select的使用
<select id="select" >
<option selected th:each="n:${listname}" th:value="${n.userID}" th:text="${n.userName}">
</option>
</select>
获取select 选中的值
var options=$("#select option:selected").val();
alert(options)
4.thymleaf(方法中获取id)
使用thymleaf传数据给后台,一定要跳页面,不然报错
thymleaf传值给onclick方法
<a th:οnclick="'javascript:del('+this+','+${user.id}+');'" ></a>
<script>
function del(obj,id) {
alert(id);
}
</script>
=======================================================================================================
1.ifranme框架的使用
绑定是用target 属性
2.获取系统时间
- 日期转字符串 format方法
java.util.Date day=new Date();
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format(day);
- 字符串转日期 parse方法
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
String dateInString = "22-12-2000";
try {
Date date = formatter.parse(dateInString);
System.out.println(date);
System.out.println(formatter.format(date));
} catch (ParseException e) {
e.printStackTrace();
}
}
3.获取session的值
先注入HttpServletRequest,在取值
@Autowired
HttpServletRequest request;
request.getSession().getAttribute("user");
4.三种参见的遍历集合方式
//2. 增强for(String str : arrays)
log.info("=================增强for(String str : arrays)遍历=====================");
for (String str : arrays) {
log.info(str);
}
//3. list.forEach((str) -> xxxxx)
log.info("=================arrays.forEach((str) -> xxxxx)遍历===================");
arrays.forEach(str -> log.info(str));
//4. 使用Iterator迭代器遍历
log.info("=================使用Iterator迭代器遍历================================");
Iterator<String> it = arrays.iterator();
while (it.hasNext()) {
String str = (String) it.next();
log.info(str);
}
- 找list对象中的某个属性,给list定义泛型,就可以用get方法了
5.DTO的使用
不得不说,真的好用
6.重定向
- 重定向是用来跳地址的,Sting直接写是用来跳页面的
7.thymleaf中表达的使用
-
thymleaf中有关于表单的使用,但是一般发表单普通的就能实现效果,暂时没必要折腾
-
// input 类型是button也发不了表单 <input type="button" value="确定"/> -
thymleaf中发送数据给后台的方法
- 啊链接
<a th:href="'/customservices/lookfile/' +${e.csid}">
- 拼接
url="/customservices/fpservice?csid="+id+"&userID="+userID
8.踩坑----mysql
发现了一个报莫名奇妙的空指针异常,反复检查,代码 感觉,没什么问题,结果真实代码没问题,而是数据库出了问题,
有时间添加数据库的时候多按了一个tab键,再随一个ctrl+s就保存了一个空对象,这就是导致空指针的根本原因,就算是删了这条数据,也会有所影响,如果再次发生这种事情,一定要注意,怎么查看,点击数据表中的设计,查看当前字段是否与数据库的条数是对应的

9.list集合通用方法
package com.zking.util;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.ArrayList;
import java.util.List;
public class PageListUtils {
/**
* 分页函数
* @param currentPage 当前页数
* @param pageSize 每一页的数据条数
* @param list 要进行分页的数据列表
* @return 当前页要展示的数据
*/
public Page getPages(Integer currentPage, Integer pageSize, List list) {
Page page = new Page();
int size = list.size();
if(pageSize > size) {
pageSize = size;
}
// 求出最大页数,防止currentPage越界
int maxPage = size % pageSize == 0 ? size / pageSize : size / pageSize + 1;
if(currentPage > maxPage) {
currentPage = maxPage;
}
// 当前页第一条数据的下标
int curIdx = currentPage > 1 ? (currentPage - 1) * pageSize : 0;
List pageList = new ArrayList();
// 将当前页的数据放进pageList
for(int i = 0; i < pageSize && curIdx + i < size; i++) {
pageList.add(list.get(curIdx + i));
}
page.setCurrent(currentPage).setSize(pageSize).setTotal(list.size()).setRecords(pageList);
return page;
}
}
10.int向上取整 的方法,三目运算符
int ceil = size / pagesize + (size % pagesize == 0 ? 0 : 1);
11.获取name值的方式(一定要导入jquery啊)
var page = $("input[name='page']").val();
12.数组越界异常
java.lang.IndexOutOfBoundsException: toIndex = 4
13.关于模板的分角色登录

-
这个模板的特点,就是可以分角色进行登录,但是点击管理员登录的时候,会将用户登录的模板切到管理员那边,管理员那边又自己写了登录的界面,如何处理这个问题呢?
正解: 使用z-index显示等级来处理,完美解决
14.thymleaf结合vue使用技巧
- 如果使用thymleaf保存后台数据,那么session应该在后台保存,如果存前台会导致thymleaf报错,找不到保存的数据
15.前后端不分离的情况下使用vue的小细节
-
是同一个域名,但还是要配置跨域,否则报错
-
后端登录的Controller要使用@ResponseBody注解,拿参数使用@RequirstBody注解,否则报错
报错信息
org.thymeleaf.exceptions.TemplateInputException: Error resolving template "xxx/xxx", template might not exist or might not be accessible by any of the configured Template Resolvers at org.thymeleaf.engine.TemplateManager.resolveTemplate(TemplateManager.java:865) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE] at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:608) ~[thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE] at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1087) [thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE] at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1061) [thymeleaf-3.0.2.RELEASE.jar:3.0.2.RELEASE]
16.避雷之使用别人的html---注意事项
- 如果页面展示不出来东西,但是有页面,解决办法之一,把别人的页面删除,重新加载一个
17.vue中v-if的使用,-- 插槽实现
<el-table-column
prop="cusState"
label="客户状态">
<template slot-scope="s">
<p v-if="s.row.cusState == '1'">正常</p>
<p v-if="s.row.cusState == '2'">流失</p>
<!-- <p v-if="cusState == '2'">流失</p>-->
</template>
</el-table-column>
18.访问templates中的页面
- templates目录里存放的html页面,不能通过url直接访问,需跳转后台才能访问,或配置静态资源路径
19.前后端分离条页面的方式
- 要么是把数据传如前台,再通过异步返回后台跳转页面
- 使用thymleaf语法进行条页面
-
误区
- 跨域和正常发请求一定要清楚区别,登录不进去就时这个原因
- vue和其他界面可以混合使用,就是不要跨域,不然拿到的session值不一样
20.退出登录如何跳页面
- 使用a链接,location跳转到主页,一般这样处理
<span style="cursor: pointer" onclick="top.location='/zhuxiao'" ><img src="images/main_20.gif" style="border:solid 0px red"/></span>
onclick="top.location='/zhuxiao'"
21.文件的上传与下载
导包:文件上传与下载的所有依赖
<!-- 导出Excel所需依赖 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.8</version>
</dependency>
- 下载
一种是刚哥的方法,简单,要指定上传路径
另一种是,网上的一种方法, 可以自定义,虽然有点复杂,但是很实用
- 上传
刚哥提供一种方法
elementui使用了一种方法
<div id="app">
<el-upload action="/customservices/importExcel/"
:show-file-list="false" accept="xlsx"
:on-success="handleImportSuccess"
:on-error="handleImportError"
style="display: inline-block;margin-right: 5px" class="eform">
<el-button type="primary"> 批量导入 <i class="el-icon-bottom"></i></el-button>
</el-upload>
</div>
<script>
var vue = new Vue({
el:'#app',
data:{
},
methods:{
handleImportSuccess() {
this.$message.success("上传成功")
},
handleImportError() {
this.$message.error("上传失败")
}
}
})
</script>
@RequestMapping("importExcel")
@ResponseBody
public void importExcel(MultipartFile file) {
boolean flag = true;
try {
InputStream in = file.getInputStream();
// //io流给ExcelReader
ExcelReader excelReader = ExcelUtil.getReader(in);
// 从excel表中得到的对象集合
List<Map<String, Object>> readAll = excelReader.readAll();
System.out.println(excelReader);
System.out.println(readAll);
//需要加入两个表,第一个用户信息表 第二个sys_user_role 用户信息关系表
for (int i = 0; i < readAll.size(); i++) {
// 创建时间
java.util.Date day = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = sdf.format(day);
// 创建人id
Users user = (Users) request.getSession().getAttribute("user");
Integer userID = user.getUserID();
//拿到字段中对应的值
readAll.get(i).get("客户编号");
readAll.get(i).get("服务类型");
readAll.get(i).get("服务概要");
readAll.get(i).get("详细信息");
Customservices customservices = new Customservices();
customservices.setCusID(readAll.get(i).get("客户编号").toString());
customservices.setStid(Integer.parseInt(readAll.get(i).get("服务类型").toString().toString()));
customservices.setCSTitle(readAll.get(i).get("服务概要").toString());
customservices.setCSDesc(readAll.get(i).get("详细信息").toString());
customservices.setCSCreateID(userID);
customservices.setCSCreateDate(format);
mapper.insert(customservices);
}
} catch (IOException e) {
flag = false;
e.printStackTrace();
} finally {
}
}
22.滑动验证
=======================================================================================================
5.报错情况
1、已解决
- 如果,登录跳转不到Controller,表达发送请求没问题
解决,检查是否有脚本阻止了表单提交事件
- 啊啊啊,thymleaf中的属性是区分大小写的,我吐了啊(花了一个小时)
- 前台一定要有提示,使用layui接受返回的结果集进行提示
2、未解决
(已解决)
使用自定义mapper查询用户,明明查的是对象,输出的确实一个属性
原因: 自定义mapper传的泛型为String,我想要的类型是Users,所以不会自动匹配,这总东西,最好是用通用mapper写
不会出错,虽然复杂一点,但能直接解决问题
6.项目流程(答辩的时候可以上台讲的)
1.服务处理
业务逻辑:查询的时候就进行账号筛选,是本账号且有被分配服务的才会显示,没有分配则不显示
项目中layui的统一引用方法
<link href="../layui/css/layui.css" rel="stylesheet" type="text/css" />
<script src="../layui/layui.js"></script>
- 服务归档中查询的实现-- 使用了嵌套for,定义一个新集合,将两个集合的字段重新add到新集合再返回给前台
7.从字符串中截取数据(小数或者整数)
//取字符串中的数字
public static String checkNum(String str) {
// String str = "abcd123和345.56jia567.23.23jian345and23or345.56";
//先判断有没有整数,如果没有整数那就肯定就没有小数
Pattern p = Pattern.compile("(\\d+)");
Matcher m = p.matcher(str);
String result = "";
if (m.find()) {
Map<Integer, String> map = new TreeMap();
Pattern p2 = Pattern.compile("(\\d+\\.\\d+)");
m = p2.matcher(str);
//遍历小数部分
while (m.find()) {
result = m.group(1) == null ? "" : m.group(1);
int i = str.indexOf(result);
String s = str.substring(i, i + result.length());
map.put(i, s);
//排除小数的整数部分和另一个整数相同的情况下,寻找整数位置出现错误的可能,还有就是寻找重复的小数
// 例子中是排除第二个345.56时第一个345.56产生干扰和寻找整数345的位置时,前面的小数345.56会干扰
str = str.substring(0, i) + str.substring(i + result.length());
}
//遍历整数
Pattern p3 = Pattern.compile("(\\d+)");
m = p3.matcher(str);
while (m.find()) {
result = m.group(1) == null ? "" : m.group(1);
int i = str.indexOf(result);
//排除jia567.23.23在第一轮过滤之后留下来的jia.23对整数23产生干扰
if (String.valueOf(str.charAt(i - 1)).equals(".")) {
//将这个字符串删除
str = str.substring(0, i - 1) + str.substring(i + result.length());
continue;
}
String s = str.substring(i, i + result.length());
map.put(i, s);
str = str.substring(0, i) + str.substring(i + result.length());
}
result = "";
for (Map.Entry<Integer, String> e : map.entrySet()) {
result += e.getValue() + ",";
}
result = result.substring(0, result.length()-1);
} else {
result = "";
}
return result;
}