1.SpringDataJpa的扩展 — 抽取
创建一个BaseRepository接口然后去继承JpaRepository和JpaSpecificationExecutor
然后在里面写我们自己想要的方法
在接口上边加上注解@NoRepositoryBean 这是为了防止底层去找SimpleJpaRepository的实现类 我们需要找我们自己的实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public interface <T,ID extends Serializable> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
Page findPageByQuery(BaseQuery baseQuery);
List<T> findByQuery(BaseQuery baseQuery);
List findByJpql(String jpql,Object...value);
}
|
然后再创建一个实现类 实现我们刚写的BaseRepository接口
再继承 SimpleJpaRepository
这样就不用覆写SpringDataJpa本身的方法了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements <T,ID> { private EntityManager entityManager; public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) { super(domainClass, em); this.entityManager = em; } @Override public Page findPageByQuery(BaseQuery baseQuery) { Sort sort = baseQuery.createSort(); Specification specs = baseQuery.createSpecifications(); Pageable pageable = new PageRequest(baseQuery.getCurrentPage(), baseQuery.getPageSize(), sort); Page page = super.findAll(specs, pageable); return page; }
@Override public List<T> findByQuery(BaseQuery baseQuery) { Sort sort = baseQuery.createSort(); Specification spec = baseQuery.createSpecifications(); List<T> list = super.findAll(spec, sort); return list; }
@Override public List findByJpql(String jpql, Object... value) { Query query = entityManager.createQuery(jpql); for (int i = 0; i < value.length; i++) { query.setParameter(i+1, value[i]); } return query.getResultList(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
public class BaseRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T,S,ID> {
@Override protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) { return new MyRepositoryFactory<T,ID>(entityManager); }
private static class MyRepositoryFactory<T,ID extends Serializable> extends JpaRepositoryFactory { private final EntityManager entityManager;
public MyRepositoryFactory(EntityManager entityManager) { super(entityManager); this.entityManager = entityManager; } @Override protected Object getTargetRepository(RepositoryInformation information) { return new BaseRepositoryImpl<T,ID>((Class<T>)information.getDomainType(),entityManager); } @Override protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { return BaseRepositoryImpl.class; } } }
|
让Spring启动的时候,找BaseRepositoryImpl的实现 —>BaseRepositoryFactoryBean可以让spring去找
BaseRepositoryImpl这个实现
在applicationContext中增加
1 2 3 4 5 6 7
| <jpa:repositories base-package="cn.itsource.repository" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory" <!-- 加这一一个属性 --> factory-class="cn.itsource.repository.impl.BaseRepositoryFactoryBean" />
|
2.抽取Service层
创建一个公共接口 IBaseService –> 完成CRUD以及三个公共方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public interface IBaseService<T,ID extends Serializable> { void save(T t); void del(ID id); T findOne(ID id); List<T> findAll(); Page findPageByQuery(BaseQuery baseQuery); List<T> findByQuery(BaseQuery baseQuery); List jpqlByQuery(String jpql,Object...value); }
|
创建一个实现类BaseServiceImpl —> 实现IBaseService —> 实现所有方法 完成所有方法 加上事务管理注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| @Transactional(propagation = Propagation.SUPPORTS,readOnly = true) public class BaseServiceImpl<T,ID extends Serializable> implements IBaseService<T, ID> {
@Autowired private BaseRepository<T,ID> baseRepository;
@Override @Transactional public void save(T t) { baseRepository.save(t); }
@Override @Transactional public void del(ID id) { baseRepository.delete(id); }
@Override @Transactional public T findOne(ID id) { return baseRepository.findOne(id); }
@Override public List<T> findAll() { return baseRepository.findAll(); }
@Override public Page findPageByQuery(BaseQuery baseQuery) { return baseRepository.findPageByQuery(baseQuery); }
@Override public List<T> findByQuery(BaseQuery baseQuery) { return baseRepository.findByQuery(baseQuery); }
@Override public List jpqlByQuery(String jpql, Object... value) { return baseRepository.findByJpql(jpql, value); } }
|
再创建IEmployeeService和EmployeeServiceImpl 分别继承接口和实现类 —> 继承之后就具备了CRUD以及公共的查询方法了
3.集成SpringMVC
(1) 导包
(2) 创建applicationContext-mvc配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <mvc:default-servlet-handler />
<context:component-scan base-package="cn.itsource.web" />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="maxUploadSize"> <value>1048576</value> </property> </bean>
|
创建web.xml 进行配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| <context-param> <param-name>contextConfigLocation</param-name> 大专栏 SpringDataJpa2"> <param-value>classpath:applicationContext.xml</param-value> </context-param>
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
<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>
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext-mvc.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
后面需要自己配置tomcat
4.加入Easyui
把easyui的文件复制到web下边
然后创建一个head.jsp 这个是专门方easyui引入的配置的
因为很多页面需要用到 所以单独抽取出来
1 2 3 4 5 6 7 8 9 10
| <%@ page contentType="text/html;charset=UTF-8" language="java" %>
<link rel="stylesheet" type="text/css" href="/easyui/themes/default/easyui.css"> <link rel="stylesheet" type="text/css" href="/easyui/themes/icon.css">
<script type="text/javascript" src="/easyui/jquery.min.js"></script> <script type="text/javascript" src="/easyui/jquery.easyui.min.js"></script> <script type="text/javascript" src="/easyui/locale/easyui-lang-zh_CN.js"></script> <script type="text/javascript" src="/easyui/plugin/jquery.jdirk.js"></script> <script type="text/javascript" src="/js/common.js"></script>
|
1 2 3
| <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%-- 需要用到easyui引入 就加上这行代码 --%> <%@include file="/WEB-INF/views/head.jsp"%>
|
然后就加入页面
树形菜单
1 2 3 4 5 6 7 8 9 10
| $("#menuTree").tree({ url:"/json/menu.json", onClick:function(node){ addTabs(node.text,node.url); } })
|
就是上边树形菜单点击事件触发之后调用下面的函数增加页签
tabs选项卡增加
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function addTabs(text,url) { if(url){ if(!$("#dataTab").tabs("exists",text)){ var content = '<iframe scrolling="auto" frameborder="0" src="'+url+'" style="100%;height:100%;"></iframe>'; $("#dataTab").tabs("add",{ title:text, content:content, closable:true }); }else{ $("#dataTab").tabs("select",text); } } }
|
5.分页
因为json中分页需要total row
![1564844780728](https://x-xzh.github.io/assets/1564844780728.png)
所以我们创建一个公共类
类里面有这两个字段 rows是显示在页面的 数据 所以用List
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class UIPage { private Long total; private List rows;
public UIPage() {}
public UIPage(Page page) { this.total = page.getTotalElements(); this.rows = page.getContent(); } }
|
在controller中 把分页查询出来的数据放到UIPage中去
1 2 3 4 5 6 7
| @RequestMapping("/page") @ResponseBody public UIPage page(EmployeeQuery employeeQuery){ Page page = employeeService.findPageByQuery(employeeQuery); UIPage uiPage = new UIPage(page); return uiPage; }
|
前台加载数据的时候 接受的参数用EmployeeQuery 但是需要在BaseQuery中设置set方法 把前台加载的页数和页面展示条数传到BaseQuery
1 2 3 4 5 6 7 8
| public void setPage(Integer page){ System.out.println(page); this.currentPage = page; } public void setRows(Integer rows){ this.pageSize = rows; }
|
前台传的参数
![1564845295829](https://x-xzh.github.io/assets/1564845295829.png)
6.头像和部门
在头像和部门的标签里加上 formatter (单元格formatter(格式化器)函数)
1 2
| <th width="20" field="headImage" formatter="headImage" >头像</th> <th width="20" field="department" formatter="department" >部门</th>
|
然后创建在js文件夹中创建一个model文件夹 里面创建一个employee的js文件
1 2 3 4 5 6 7 8 9 10
| function department(value) { if(value){ return value.name; } } function headImage(value) { if(value){ return "<img src='"+value+"' />"; } }
|
7.解决懒加载问题
在wei.xml里面加
1 2 3 4 5 6 7 8 9
| <filter> <filter-name>openEntity</filter-name> <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>openEntity</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
方法一:在实体类建立关系的上面加上注解
1 2 3 4
| @ManyToOne @JoinColumn(name = "department_id") @JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"}) private Department department;
|
方法二:因为方法一只能对单个有效 有很多类都需要的时候 很麻烦
(1) 创建一个新的类(重写com.fasterxml.jackson.databind.ObjectMapper)
1 2 3 4 5 6 7
| public class CustomMapper extends ObjectMapper { public CustomMapper(){ this.setSerializationInclusion(JsonInclude.Include.NON_NULL); this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); } }
|
(2) 在applicationContext-mvc.xml中配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <mvc:annotation-driven > <mvc:message-converters> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>application/json; charset=UTF-8</value> <value>application/x-www-form-urlencoded; charset=UTF-8</value> </list> </property> <property name="objectMapper"> <bean class="cn.itsource.common.CustomMapper"></bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
|
8.高级查询
页面准备好之后 需要回显部门下拉框
先去repositroy去写一个IDepartmentRepository接口
再去service把IDepartmentService接口和实现类写好
再创建一个UtilController
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Controller @RequestMapping("/util") public class UtilController { @Autowired private IDepartmentService departmentService;
@RequestMapping("/departmentList") @ResponseBody public List<Department> departmentList(){ List<Department> list = departmentService.findAll(); return list; } }
|
页面准备for表单 点击搜索的时候 加载数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| $(function () { var searchForm = $("#searchForm"); var employeeGrid = $("#employeeGrid");
$("a[data-method]").on("click",function () { var methodName = $(this).data("method"); itsource[methodName](); }) var itsource = { search:function () { var parme = searchForm.serializeObject(); employeeGrid.datagrid("load",parme); } } })
|
在EmployeeQuery增加几个属性和条件
1 2 3 4 5 6 7 8
| public Specification createSpecifications() { Specification<Employee> specification = Specifications.<Employee>and() .like(StringUtils.isNotBlank(this.username), "username", "%" + this.username + "%") .like(StringUtils.isNotBlank(this.email), "email", "%" + this.email + "%") .eq(this.departmentId != null,"department.id",this.departmentId) .build(); return specification; }
|