系統配置環境參考:https://my.oschina.net/u/4108086/blog/3069786javascript
今天的目標是完成web與後臺的聯動的css
一.項目結構:html
1.common:工具類前端
2.domain:主體類java
3.repository:持久化類/接口jquery
4.query:查詢類web
5.service:服務層spring
6.web:前端數據庫
①controller:控制層json
二.今日目標
1.完成SpringDataJpa的擴展抽取,而後就能夠直接使用了
2.完成流程搭建,並運行成功
①後臺代碼搭建
②前臺主頁連通
③完善類與展現頁面
④加入高級查詢
⑤功能擴展
三.代碼完成
[toc]
# 一.SpringDataJpa擴展
> 對SpringDataJpa的原來功能進行了相應的增長(代碼是拷備)## 1.BaseRepository 接口
> @NoRepositoryBean:讓SpringdataJpa不要自動爲它生成子類
@NoRepositoryBean public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T,ID>, JpaSpecificationExecutor<T> { //根據Query拿到分頁對象(分頁) Page findPageByQuery(BaseQuery baseQuery); //根據Query拿到對應的全部數據(不分頁) List<T> findByQuery(BaseQuery baseQuery); //根據jpql與對應的參數拿到數據 List findByJpql(String jpql,Object... values); }
## 2.BaseRepositoryImpl 實現 BaseRepository
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.createSpec(); //第二步:拿到排序的值 Sort sort = baseQuery.createSort(); //第三步:根據條件查詢分頁數據而且返回 Pageable pageable = new PageRequest(baseQuery.getJpaPage(), baseQuery.getPageSize(),sort); Page<T> page = super.findAll(spec, pageable); return page; } @Override public List<T> findByQuery(BaseQuery baseQuery) { //第一步:拿到全部高級查詢條件 Specification spec = baseQuery.createSpec(); //第二步:拿到排序的值 Sort sort = baseQuery.createSort(); //第三步:拿到數據返回 return findAll(spec, sort); } @Override public List findByJpql(String jpql, Object... values) { //第一步:建立Query對象 Query query = entityManager.createQuery(jpql); //第二步:把值設置到Query對象中去 if (values!=null) { for (int i = 0; i < values.length; i++) { query.setParameter(i + 1, values[i]); } } //第三步:返回數據 return query.getResultList(); } }
## 3.讓SpringDataJpa使用咱們本身的實現
> 原來默認使用SimpleJpaRepository來實現,把它修改爲BaseRepositoryImpl### 3.1 BaseRepositoryFactoryBean
/** * 若是要擴展SpringDataJpa必需寫它 */ 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; } } }
### 3.2 applicationContext.xml配置
> 關鍵就是factory-class配置
<!-- 集成SpringDataJpa (這層單獨掃描)--> <jpa:repositories base-package="cn.itsource.aisell.repository" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager" factory-class="cn.itsource.aisell.repository.BaseRepositoryFactoryBean" ></jpa:repositories>
### 3.3使用的時候繼承BaseRepository
public interface EmployeeRepository extends BaseRepository<Employee,Long>{...}
# 二.Service層的調用
BaseServiceImpl 實現 IBaseService
IEmployeeService 繼承 IBaseService
> 注意點泛型注入
@Autowired private BaseRepository<T,ID> baseRepository;
# 三.集成SpringMVC與EasyUI
## 3.1 noSession問題
> 咱們在關閉了EntityManager以前,依然在使用它操做數據庫(懶加載時出現)
>> 解決方案:web.xml中添加OpenEntityManagerInViewFilter
<!-- 解決no-session的問題 -->
<filter> <filter-name>openEntityManager</filter-name> <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class> </filter> <filter-mapping> <filter-name>openEntityManager</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
## 3.2 no serializer問題
> 緣由:jpa的懶加載對象本身爲加一些屬性("hibernateLazyInitializer","handler","fieldHandler") 會影響到SpringMVC返回Json(由於返回時有個內省機制)
### 解決方案一:加註解
`@JsonIgnoreProperties(value={"hibernateLazyInitializer","handler","fieldHandler"})`
### 解決方案二:一勞永逸- 重寫:ObjectMapper
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; //重寫了原生的映射關係 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.aisell.common.CustomMapper"></bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven>
## 3.3 分頁獲取數據
> 後臺返回的是Page對象{content:..,totalElements:..}
>> 前臺要拿代碼是{rows:..,total:...}
>>> 它們的結果對應不上- 搞了一個UIPage
public class UIPage <T>{ private List<T> rows; private Long total; public UIPage(Page page) { this.rows = page.getContent(); this.total = page.getTotalElements(); } //省略getter與setter }
- 返回的時候代碼以下:
@RequestMapping("/page") @ResponseBody public UIPage page(EmployeeQuery query){ return new UIPage(employeeService.findPageByQuery(query)); }
## 3.4 分頁傳數據
> 傳的是page與rows,可是咱們以前的query名稱沒對應上
- BaseQuery加上兼容
//爲了兼容前臺的easyui而準備的,添加額外的setter
public void setPage(int page) { this.currentPage = page; } public void setRows(int rows) { this.pageSize = rows; }
## 3.5 高級查詢
- 高級查詢的時候獲取對應的表單值
### 引入[jquery.jdirk.js]
> 它對jQuery的功能進行擴展
`<script type="text/javascript" src="/easyui/plugin/jquery.jdirk.js"></script>`
### 獲取表單的功能
search(){ //直接獲取到表單中的全部值 var params = $("#searchForm").serializeObject(); //進行相應的查詢 $("#employeeGrid").datagrid("load",params); }
## 3.6 擴展部分
一.排序功能
/** * 公共的條件與規範 */ public abstract class BaseQuery { ... //兼容Easyui的排序 public void setSort(String sort) { this.orderByName = sort; } public void setOrder(String order) { this.orderByType = order; } }
2.employee.js支持 : 在須要支持的字段添加sortable="true"屬性
<th width="20" field="headImage" data-options="formatter:formatImage">頭像</th> <th width="20" field="username" sortable="true">用戶名</th> <th width="20" field="password">密碼</th> <th width="20" field="email">郵件</th> <th width="20" field="age" align="right" sortable="true">年齡</th> <th width="20" field="department" align="center" data-options="formatter:formatDept" sortable="true">部門</th>
3.隱藏字段
能夠找到http://www.easyui-extlib.com/ -> grid部分找到這個效果
並獲取須要的支持和源碼;
須要的部分:
<!-- datagrid-隱藏列的支持 --> <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>
在table標籤中添加 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">