簡介:Spring Data JPA 其實就是JDK方式(還有一種cglib的方式需要Class)的動態代理 (需要一個接口 有一大堆接口最上邊的是Repository接口來自org.springframework.data.repository,
還有CrudRepository接口及一個實現類SimpleJpaRepository),只要有接口就可以查詢數據庫了,實際上就是proxy的方法,具體查詢的方法有兩種
一種是簡單式就是方法名為findBy+屬性名+(AndOrIsEquals等)
另一種是自定義的方法就是屬性名是瞎起的向abc xyz什么的根本找不到這個屬性,這時就可以用sql或者jpql兩種語言
@Query(nativeQuery=false是默認的不用寫,可以用jpql語言,value="from standard where name=?")
@Query(nativeQuery=true必須寫,代表用sql語言,value="select * from standard where c_name=?")
public List<Standard> findByAbc(String name) 參數就是?
如果是增刪改操作還要加上@Modifying
分頁:對於分頁查詢,更是簡便
public interface StandardDao extends JpaRepository<Standard, Integer>{ //繼承的接口中已經包含分頁查詢接口中的方法
所以只需要在service的實現類中
@Service
@Transactional
public class StandardServiceImpl implements StandardService { //調用dao接口中看不見的findAll()方法
public Page<Standard> pageQuery(Pageable pageable) {
return standardDao.findAll(pageable);
}
這個PageAble也是個接口,他的實現類封裝了page和rows兩個瀏覽器提交過來的參數(發自easyui的datagrid的url請求,要求這個datagrid有pagination屬性)
Pageable pageable = new PageRequest(page-1, rows);
注意page的索引是從0開始的,0表示第一頁,所以要減一
page是分頁查詢的頁碼 rows是每頁幾條
在Web層的Action中只需要通過Spring框架自動注入Service接口的實現類對象
@Autowired
private StandardService standardService;
調用其中方法
Page<Standard> page = standardService.pageQuery(pageable);
即可得到Page接口的實現類對象,
page對象中的內容正是easyui的datagrid組件中必需的內容,但是名字不同不叫rows而是content
{
"total":86,
"rows":[
{"id":101,"name":"jack","age":20},
{"id":102,"name":"rose","age":21},
{"id":103,"name":"lili","age":22}
]
}
通過page.getTotalElements()獲得總記錄數"total"
通過page.getContent()獲得根據分頁查詢到內容
通過輸出到控制台
System.out.println("總記錄數:"+page.getTotalElements());
System.out.println("當前頁記錄:"+page.getContent());
發現結果分別是Number類型和List集合並不是我們需要的json格式
通過Map集合轉換為上邊的json格式,把鍵值設置為我們需要的"rows"
Map<String, Object> map = new HashMap<>();
map.put("total", page.getTotalElements());
map.put("rows", page.getContent());
使用jsonlib的jsonObject轉換成json字符串格式
String json = JSONObject.fromObject(map).toString();
發回瀏覽器
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
保存:頁面提交表單<form id="standardForm" action="${pageContext.request.contextPath}/standardAction_save.action" method="post">
找到standardAction_save.action所指向的save方法
用自動注入的service調用save方法
standardService.save(model);
在service的實現類中
@Service
@Transactional
public class StandardServiceImpl implements StandardService {
調用自動注入的dao
@Autowired
private StandardDao standardDao;
的方法
public void save(Standard model) {
standardDao.save(model);
}
這個save(model)方法在dao的接口中看不到,在dao繼承的接口CrudRepository中已經定義,增加修改都是save,沒有add和update
model來自實現ModelDriven接口
implements ModelDriven<T>
下邊是向上抽取出的BaseAction父類
public class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
protected T model;//這里需要new對象的,在構造方法中生成的
public T getModel() {
return model;
}
//子類action創建,父類無參構造執行,獲取子類繼承BaseAction中泛型Class
/*
* 參數化類型Type:BaseAction<Standard> -- cn.itcast.bos.web.action.common.BaseAction<cn.itcast.bos.base.Standard>
* 實際類型參數:《》中class叫實際類型參數
* */
public BaseAction() {
try {
//第一步:獲取當前運行class-子類
Class clzz = this.getClass();
System.err.println(clzz);
//第二步:獲取子類繼承父類的class--參數化類型
/*Type getGenericSuperclass() Type:接口 Class是Type實現類
返回表示此 Class 所表示的實體(類、接口、基本類型或 void)的直接超類的 Type。 */
Type type = clzz.getGenericSuperclass();
System.err.println(type);
//將Type接口轉為子接口 ParameterizedType
ParameterizedType parameterizedType = (ParameterizedType) type;
//第三步:獲取實際類型參數-model對象class
Type[] types = parameterizedType.getActualTypeArguments(); //[cn.itcast.bos.base.Standard]
System.err.println(types);
//將Type接口轉為實現類Class
Class clzzzzzzzzzzzz = (Class) types[0];
//第四步:將class實例化
model = (T) clzzzzzzzzzzzz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
//通過屬性驅動獲取當前頁,每頁顯示記錄數
//page-1
protected Integer page;
protected Integer rows;
public void setPage(Integer page) {
this.page = page-1;
}
public void setRows(Integer rows) {
this.rows = rows;
}
/**
* @Description: 將service中查詢到Page對象轉為分頁需要json數據
* @param page
* @param excluds
*
*/
public void java2Json(Page<T> page, String[] excluds){
try {
Map<String, Object> map = new HashMap<>();
map.put("total", page.getTotalElements());
map.put("rows", page.getContent());
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excluds);
String json = JSONObject.fromObject(map, jsonConfig).toString();
System.err.println(json);
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description: 將List集合轉為json數組
*/
public void java2Json(List list , String[] excluds){
try {
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excluds);
String json = JSONArray.fromObject(list, jsonConfig).toString();
System.err.println(json);
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
} catch (Exception e) {
e.printStackTrace();
}
}
}
關於no session問題
下邊在分頁查詢快遞員時,如果不處理courier實體中外鍵關聯的集合采用懶加載方式而導致no session異常,也就是
Page<Courier> page = courierService.pageQuery(model, pageable);執行后已經查詢出快遞員,但在轉json的時候,
session已經關了,懶加載的集合沒有session無法加載
解決方法一,
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(new String[]{"fixedAreas", "company"});
忽略掉fixedAreas集合就可以了,不用它
相關代碼如下:
@Action("courierAction_pageQuery")
public String pageQuery() throws Exception {
Pageable pageable = new PageRequest(page, rows);
Page<Courier> page = courierService.pageQuery(model, pageable);
this.java2Json(page, new String[]{"fixedAreas"});
/*Map<String, Object> map = new HashMap<>();
map.put("total", page.getTotalElements());
map.put("rows", page.getContent());
//將快遞員對象中集合屬性fixedAreas排除掉(忽略該屬性,最終在快遞員對象不存在屬性)
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(new String[]{"fixedAreas", "company"});
String json = JSONObject.fromObject(map, jsonConfig).toString();
System.err.println(json);
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);*/
return NONE;
}
解決方法二,
也可以將session(Spring data JPA中是EntityManager)延長至web層
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
解決方法三
@ManyToMany(fetch=FetchType.EAGER, mappedBy = "couriers")//jpa默認策略 集合形式延遲加載
private Set<FixedArea> fixedAreas = new HashSet<FixedArea>();