wisdomsell-day2(智能商贸系统第二天)
1.抽取repository的父接口
/**
因为扫描包扫描的是repository下面的所有,如果不打上该注释,就会实现它
父接口不能确定类型
@NoRepositoryBean告诉spring不要去实现它
*/
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T> {
}
同时子类也需要改为继承该接口
public interface EmployeeRepository extends BaseRepository<Employee,Long>
2.创建service层
2.1创建父接口
这里除了常规的CRUD以外,另外多写了3个方法
创建好后,再创建子接口去继承
public interface IBaseService<T,ID extends Serializable> {
void save(T t);
void delete(ID id);
T findOne(ID id);
List<T> findAll();
//扩展操作
//1.根据查询对象进行查询
List<T> queryAll(BaseQuery query);
//2.根据查询对象拿到分页数据
Page<T> queryPage(BaseQuery query);
//3.根据JPQL进行查询
/**
* 主要是为了去解决你必须手动写jpql来查询的东西
* params 参数
* 这里属性和值都是不确定的
*/
List<Object> queryByJpql(String jpql,Object... params);
}
2.2创建父接口的实现类
注意事项:1:一般情况来说,因为查询是不需要事物的,而且查询的时候多点,所以可以在类上打上注解,但是不一定绝对,需要根据实际情况来定2:因为这个实现类注入的是接口,但是父类接口是没有被spring实现的,这就是为什么加入泛型的原因3:以后可能出现需要用到写jpql的情况
创建好父类实现后,再创建一个子类实现类,并继承父类
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class BaseServiceImpl<T,ID extends Serializable> implements IBaseService<T,ID> {
/**
* 这个父接口本身没有实现
* 所以注入的其实是他的所有子接口实现(),所以spring不知道是哪个接口
* 所以为了让spring知道,在后面加入泛型
* 父接口的实现,这个类就是一个父类,根本就不用它创建对象,所以最好把该类变为抽象类,免得去创建对象
* 至于最后如何确定类型,则由最后的子类来确定
* 这里你写abstract只是断念想,你不写也是可以的
*/
@Autowired
private BaseRepository<T,ID> baseRepository;
//保证事物都是同一个线程中的
@PersistenceContext
private EntityManager entityManager;
@Override
@Transactional
public void save(T t) {
baseRepository.save(t);
}
@Override
@Transactional
public void delete(ID id) {
baseRepository.delete(id);
}
@Override
public T findOne(ID id) {
return baseRepository.findOne(id);
}
@Override
public List<T> findAll() {
return baseRepository.findAll();
}
//根据查询对象进行查询
@Override
public List<T> queryAll(BaseQuery query) {
//拿到查询规则
Specification spec = query.creatSpec();
//进行查询
return baseRepository.findAll(spec);
}
//根据查询对象拿到分页数据
@Override
public Page<T> queryPage(BaseQuery query) {
//1.拿到排序对象
Sort sort = query.createSort();
//2.拿到分页对象
Pageable pageable = new PageRequest(query.getJpaCurrentPage(),query.getPageSize(),sort);
//3.拿到查询规则
Specification spec = query.creatSpec();
//4.进行查询
return baseRepository.findAll(spec,pageable);
}
//根据JPQL进行查询
@Override
public List<Object> queryByJpql(String jpql, Object... params) {
//1.创建query对象
Query query = entityManager.createQuery(jpql);
//2.循环params参数,设置值从1开始
for (int i=0;i<params.length;i++){
query.setParameter(i+1,params[i]);
}
//返回数据
return query.getResultList();
}
}
3.测试service
点击注解进入就可以发现该注解是否有元注解
//@Inherited 只要有这个元注解,表示该注解是可以被继承的
public class test extends EmployeeRepositoryTest {
@Autowired
private IEmployeeService iEmployeeService;
@Test
public void testFindAll()throws Exception{
List<Employee> list = iEmployeeService.findAll();
list.forEach(e-> System.out.println(e));
}
//根据用户名来进行查询
@Test
public void testQueryAll()throws Exception{
EmployeeQuery employeeQuery = new EmployeeQuery();
employeeQuery.setUsername("1");
System.out.println(iEmployeeService.queryAll(employeeQuery));
}
//根据查询对象拿到分页数据
@Test
public void testQueryPage()throws Exception{
EmployeeQuery employeeQuery = new EmployeeQuery();
employeeQuery.setUsername("admin");
employeeQuery.setCurrentPage(1);
employeeQuery.setPageSize(10);
System.out.println(iEmployeeService.queryPage(employeeQuery));
}
}
4.准备Spring-MVC
第一天没用的上传解析器在这里就可以用了,注意名字只能为multipartResolver
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--1.扫描包-->
<context:component-scan base-package="com.yyk.aisell.controller"></context:component-scan>
<!--2.SpringMVC注解支持-->
<mvc:annotation-driven/>
<!--3.静态资源放行-->
<mvc:default-servlet-handler/>
<!--4.视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--5.上传解析 暂时不用-->
<!--5.上传解析器 CommonsMultipartResolver-->
<!-- 注意:上传解析器的id必需:multipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>10485760</value>
</property>
</bean>
5.准备web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<!--这里必须xml里面要用高版本的,至少都要2.4版本-->
<!--先配置一个监听器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--读取spring配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--核心控制器-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--读取springMVC的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
<!--核心控制器在启动tomcat的时候就自动创建-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--编码过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
6.controller层以及分页BUG
我们在下面代码分页跳转的时候,发现页面无法显示内容,查看F12后发现是后台穿回去的数据和前端需要的不一样所导致的,在这里可以有两种办法,一种,用map的形式将所需要的key和value值传入,另外一种则是新建一个类
@Controller
@RequestMapping("/employee")
public class EmployeeController extends BaseController {
@Autowired
private IEmployeeService employeeService;
@RequestMapping("/index")
public String index(){
return "employee/index";
}
/**
* 此时你访问page,发现页面没有显示数据,原因是后台的头和前端的头不一样
* 前端显示是 rows total
*
后台传过去的是 content
0
id 1
username "admin"
password "48d05cc43f3bfe2510394e8dfcef919a"
email "admin@itsource.com"
age 34
所以解决的办法有两个:一个是创建map集合,另外一个就是创建一个类,将字段传进去,这里选择后一种方法
*/
@RequestMapping("/page")
@ResponseBody
public EasyUiPage list(EmployeeQuery employeeQuery){
Page<Employee> page = employeeService.queryPage(employeeQuery);
EasyUiPage easyUiPage = new EasyUiPage(page);
return easyUiPage;
}
@RequestMapping("/list")
@ResponseBody
public List<Employee> findAll(){
return employeeService.findAll();
}
//删除数据
@RequestMapping("/delete")
@ResponseBody
public JsonResult delete(Long id){
try {
employeeService.delete(id);
return new JsonResult();
}catch (Exception e){
return new JsonResult(false,e.getMessage());
}
}
}
6.1创建EasyUIPage
这个就是独属于前台的
public class EasyUiPage<T> {
private Long total;
private List<T> rows = new ArrayList<>();
//在这里直接将后台的page参数传进去,变为前台需要的参数
public EasyUiPage(Page page) {
this.total = page.getTotalElements();
this.rows = page.getContent();
}
@Override
public String toString() {
return "EasyUiPage{" +
"total=" + total +
", rows=" + rows +
'}';
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
public List<T> getRows() {
return rows;
}
public void setRows(List<T> rows) {
this.rows = rows;
}
}
6.2实现分页
发送请求过去,并且带了参数,只是这两个值在第一天的BaseQuery类中没有,所以在类中加入两个set方法即可,因为传参,是调用的set方法
//为了兼容easyui提供的方法,因为后台给的是rows和page
public void setPage(int page){
this.currentPage=page;
}
public void setRows(int rows){
this.pageSize=rows;
}
7.高级查询功能实现
7.1准备工具栏
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%--jsp如果有相同的头部,直接提取出去,在这里进行引入--%>
<%@include file="/WEB-INF/views/head.jsp"%>
<%--引入当前模块对应的js--%>
<script src="/js/model/employee.js">
</script>
</head>
<body>
<div id="toolbar" style="padding:5px;height:auto">
<div style="margin-bottom:5px">
<a href="#" data-method="add" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a>
<a href="#" data-method="update" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a>
<a href="#" data-method="delete" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a>
</div>
<form id="searchForm" method="post">
用户名: <input name="username" class="easyui-textbox" style="width:80px">
邮件: <input name="email" class="easyui-textbox" style="width:80px">
<a href="#" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
</form>
</div>
<%--fit自适应,有了以后width和height就失去作用了--%>
<table id="datagrid" class="easyui-datagrid"
data-options="url:'/employee/page',fitColumns:true,singleSelect:true,fit:true,toolbar:'#toolbar',pagination:true">
<thead>
<tr>
<th data-options="field:'id',width:100">编码</th>
<th data-options="field:'username',width:100">名称</th>
<th data-options="field:'age',width:100,align:'right'">年龄</th>
<th data-options="field:'password',width:100">密码</th>
<th data-options="field:'email',width:100">邮件</th>
</tr>
</thead>
</table>
</body>
</html>
7.2将js的引用头提取出来
这里引入了一个Jquery的扩展包,能够方便处理数组和json的转换,因为easyUi没有实现这个功能
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入easyUI样式--%>
<link rel="stylesheet" type="text/css" href="/easyui/themes/default/easyui.css">
<%--引入图标--%>
<link rel="stylesheet" type="text/css" href="/easyui/themes/icon.css">
<%--引入jquery--%>
<script type="text/javascript" src="/easyui/jquery.min.js"></script>
<%--jQuery的扩展包 --%>
<script type="text/javascript" src="/easyui/plugin/jquery.jdirk.js"></script>
<%--easyUI核心文件--%>
<script type="text/javascript" src="/easyui/jquery.easyui.min.js"></script>
<%--引入一个国际化--%>
<script type="text/javascript" src="/easyui/locale/easyui-lang-zh_CN.js"></script>
7.3将不同的属性的js代码单独写
不同类型对应不同的js代码,单独创建js来放置
$(function () {
//常用的元素都先在这里获取到
var datagrid = $("#datagrid");
var searchForm = $("#searchForm")
//事件
$("*[data-method]").on("click",function () {
//1.拿到当前对应的方法名
var methodName = $(this).data("method");
//2.调用方法
itsource[methodName]();
})
itsource ={
add(){
alert("add");
},
update(){alert("update");},
delete(){
//1.获取选中的行
var row = datagrid.datagrid("getSelected");
//2.如果这一行不存在(给出提示,后台代码不再执行)
if(!row){
$.messager.alert('提示','请选中一行再来删除,好嘛!',"warning");
return;
}
//3.让用户确定是否删除
$.messager.confirm('确认','您确认想要删除记录吗?',function(r){
if (r){
//4.通过Ajax请求进行删除
// 参数一:请求路径 参数二:请求参数 参数三:回调
// result:是后端返回的结果
$.get("/employee/delete",{id:row.id},function (result) {
if(result.success){
//5.刷新页面
datagrid.datagrid("reload");
}else{
//给出错误提示
$.messager.alert('提示',`删除失败,原因是:${result.msg}`,"error");
}
})
}
});
},
//高级查询功能
search(){
//1.拿到查询的值
var params = searchForm.serializeObject();
//2.进行查询
datagrid.datagrid("load",params);
}
};
})
8.删除功能实现
删除的思想:当我们点击删除时,如果没有点击任意一行,就提示:请点击一行,如果点击到任意一行,就提示是否进行删除,如果删除失败,则返回一个消息,删除成功就重新加载该页面,可以先考虑从后台代码写
8.1删除后台
public class JsonResult {
//默认删除是成功的
private boolean success = true;
//如果失败,就回返回消息
private String msg ;
//如果构造方法里面有参数就是删除失败,没有参数则成功
public JsonResult(boolean success,String msg){
this.success = success;
this.msg = msg;
}
public JsonResult() {
}
public boolean getSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
8.2控制层
//删除数据
@RequestMapping("/delete")
@ResponseBody
public JsonResult delete(Long id){
try {
employeeService.delete(id);
return new JsonResult();
}catch (Exception e){
return new JsonResult(false,e.getMessage());
}
}
}
8.3前台
delete(){
//1.获取选中的行
var row = datagrid.datagrid("getSelected");
//2.如果这一行不存在(给出提示,后台代码不再执行)
if(!row){
$.messager.alert('提示','请选中一行再来删除,好嘛!',"warning");
return;
}
//3.让用户确定是否删除
$.messager.confirm('确认','您确认想要删除记录吗?',function(r){
if (r){
//4.通过Ajax请求进行删除
// 参数一:请求路径 参数二:请求参数 参数三:回调
// result:是后端返回的结果
$.get("/employee/delete",{id:row.id},function (result) {
if(result.success){
//5.刷新页面
datagrid.datagrid("reload");
}else{
//给出错误提示
$.messager.alert('提示',`删除失败,原因是:${result.msg}`,"error");
}
})
}
});
},