Spring Data Jpa扩展
针对repository层进行抽取优化
BaseRepository接口
@NoRepositoryBean
public interface BaseRepository<T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T>{
//根据Query拿到分页对象(分页)
Page findPageByQuery(BaseQuery baseQuery);
}
BaseRepositoryImpl 实现
首先添加BaseRepositoryImpl类,实现BaseRepository接口,继承SimpleJpaRepository类,使其拥有Jpa Repository的基本方法。
我们发现Repository有两个构造函数:
l SimpleJpaRepository(JpaEntityInformation entityInformation, EntityManager entityManager)
l SimpleJpaRepository(Class domainClass, EntityManager em)
这里我们实现第二个构造函数,拿到domainClass和EntityManager两个对象
public class BaseRepositoryImpl<T,ID extends Serializable> extends SimpleJpaRepository<T,ID> implements BaseRepository<T,ID> {
private final EntityManager entityManager;
//必需要实现父类的这个构造器
public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
this.entityManager = em;
}
@Override
public Page findPageByQuery(BaseQuery baseQuery) {
//第一步:拿到所有高级查询条件
Specification spec = baseQuery.createSpecification();
//第二步:拿到排序的值
Sort sort = baseQuery.createSort();
//第三步:根据条件查询分页数据并且返回
Pageable pageable = new PageRequest(baseQuery.getJpaPage(), baseQuery.getPageSize(),sort);
Page<T> page = super.findAll(spec, pageable);
return page;
}
自定义RepositoryFactoryBean
使用自定义RepositoryFactoryBean来替代默认的RepositoryFactoryBean ,使得能让spring找到自定义的类
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); //注:这里创建是我们的自定义类
}
//继承JpaRepositoryFactory后,把返回的对象修改成我们自己的实现
private static class MyRepositoryFactory<T,ID extends Serializable> extends JpaRepositoryFactory{
private final EntityManager entityManager;
/**
* Creates a new {@link JpaRepositoryFactory}.
*
* @param entityManager must not be {@literal null}
*/
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;
}
}
}
xml配置
<jpa:repositories base-package="cn.itsource.pss.repository"
transaction-manager-ref="transactionManager"
entity-manager-factory-ref="entityManagerFactory"
factory-class="cn.itsource.pss.repository.BaseRepositoryFactoryBean"
/>
查询功能
Service层
-
抽取父接口 IBaseService
-
子接口IEmployeeService 继承 IBaseService并指定泛型
-
添加BaseServiceImpl 实现 IBaseService
-
添加EmployeeServiceImpl继承 IBaseService, 实现IEmployeeService
注意:泛型使用规范;
注入 BaseRepository对象时,添加泛型
@Autowired private BaseRepository<T,ID> baseRepository;
配置spring-mvc
1.导包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
2.配置applicationContext-mvc.xml
<?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
">
<!-- 对静态资源进行放行 -->
<mvc:default-servlet-handler />
<!-- 扫描controller部分的包 -->
<!-- @Component组件, @Repository持久层, @Service业务逻辑层, and @Controller控制器 -->
<context:component-scan base-package="cn.itsource.pss.web" />
<!-- 添加mvc对@RequestMapping等注解的支持 -->
<mvc:annotation-driven />
<!-- ViewResolver 视图解析器 (struts2视图类型类似) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 设置视图路径的前后缀,该配置可以让我们写视图路径的时候更简单。 -->
<!-- 希望跳转jsp是[/WEB-INF/views/前缀][xxx变量][.jsp后缀] -->
<!-- * @see #setPrefix -->
<property name="prefix" value="/WEB-INF/views/" />
<!-- * @see #setSuffix -->
<property name="suffix" value=".jsp" />
</bean>
<!-- 错误:提示告诉开发者你没有配置文件上传解析器。 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为1MB -->
<property name="maxUploadSize">
<value>1048576</value>
</property>
</bean>
</beans>
3.配置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">
<!-- 读取SpringMVC -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 启动Spring的监听器 -->
<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>
<!-- 告诉SpringMVC到哪里去找配置文件 -->
<param-name>contextConfigLocation</param-name>
<!-- 注意:这里只读取springmvc的xml -->
<param-value>classpath:applicationContext-mvc.xml</param-value>
</init-param>
<!-- Servlet默认在每一次访问的时候创建 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Controller层
- 父类抽取
- @Controller注解
主页面
1.拷贝easyui文件夹到webapp根目录下
2.主页面跳转的controller
3.main.jsp
注意: 抽取head.jsp专门用来导入需要使用的easyui及其余共享的引入文件
员工查询页面
-
employee.jsp,用来展示数据
-
准备一个UIpage.java,解决SpringDataJpa返回的数据和EasyUI中的数据匹配不上的问题
public class UiPage { private long total; //总条数 private List rows; //每页数据 public UiPage(){} public UiPage(Page page){ total = page.getTotalElements(); rows = page.getContent(); } }
-
修改BaseQuery 中的参数对应
public abstract class BaseQuery { …. //兼容Easyui的分页 public void setPage(int page) { this.currentPage = page; } public void setRows(int rows) { this.pageSize = rows; } }
-
controller层的方法(返回一个包装过的类)
//查询分页数据 @RequestMapping("/page") @ResponseBody public UiPage page(EmployeeQuery query){ return new UiPage(employeeService.findPageByQuery(query)); }
完善Employee对象
-
建立employee与department之间的关联(many2one)
-
配置web.xml解决noSession问题
<!-- 加上OpenEntityManager --> <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>
-
解决department对象设置的懒加载引起的"No serializer found for class"问题
创建新类
public class CustomMapper extends ObjectMapper { public CustomMapper() { this.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 设置 SerializationFeature.FAIL_ON_EMPTY_BEANS 为 false this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); } }
配置applicationContext-mvc.xml
<!-- Spring MVC 配置 --> <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> <!-- No serializer:配置 objectMapper 为我们自定义扩展后的 CustomMapper,解决了返回对象有关系对象的报错问题 --> <property name="objectMapper"> <bean class="cn.itsource.pss.common.CustomMapper"></bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
高级查询
- employee.jsp页面
- employee.js书写
- 页面查询部门信息时,需要在下拉框展示,因此单独用UtilController来查询
- 检查EmployeeQuery是否有模糊查询及部门的准确查询
功能拓展
排序功能
-
easyui返回的排序名称和类型为 sort和order ,需要更改一下 BaseQuery 中set方法中形式参数名称
-
employee.jsp中需要设置 sortable=“true”
<th width="20" field="username" sortable="true">用户名</th>
隐藏字段
-
通过easyui扩展库查询到该方法
-
导入依赖的css和js文件(可在demo的f12中进行查看拷贝)
<link href="/easyui/plugin/datagrid/jeasyui.extensions.datagrid.css" rel="stylesheet" /> <script src="/easyui/plugin/menu/jeasyui.extensions.menu.js"></script> <script src="/easyui/plugin/datagrid/jeasyui.extensions.datagrid.getColumnInfo.js"></script> <script src="/easyui/plugin/datagrid/jeasyui.extensions.datagrid.columnToggle.js"></script>
-
给datagird配置enableHeaderClickMenu=“true”
<table id="employeeGrid" class="easyui-datagrid" data-options="fit:true,fixed:true,fitColumns:true,toolbar:'#tb',singleSelect:true" url="/employee/page" iconCls="icon-save" enableHeaderClickMenu="true" rownumbers="true" pagination="true">