전체 쿼리 페이지의 실행 코드를 공유하기 전에 먼저 실행 프로세스를 이해하십시오.
1. 일반적으로 MyBatis 플러그인 인터셉터를 사용하여 SQL 실행 전에 인터셉트하고 쿼리 문에 한계 XX를 추가합니다.
2. 페이지 객체를 사용하여 전체 실행 프로세스를 실행하십시오. 이 페이지 객체는 Java에 프론트 엔드 페이지 매김 구성 요소를 작성해야합니다.
3.이 페이지 매김 아키텍처를 지원하기 위해 비교적 완전한 3 층 엔터티, DAO 및 서비스 세트를 사용하십시오.
4.이 페이지에 사용 된 일부 보조 클래스
참고 : 많은 콘텐츠가 공유됩니다. 필요한 항아리를 하나씩 나열하지는 않습니다. 이 페이지 매김 기능을 사용하면 밤에 항아리 패키지를 찾으십시오. Maven은 버전 충돌 및 기타 장점을 줄일 수 있으므로 Maven 패키지를 사용하여 가능한 한 많이 가져옵니다.
이 쉬운 페이징 기능을 최대한 빨리 사용할 수 있다고 말할 수 있습니다. 이해하지 못하면 QQ에 저를 추가하여 함께 토론하십시오. 맹세하지 마세요! 또한이 기사는 비교적 클 수 있지만 시간이 걸리고 읽고 연습하는 것은 분명히 많이 얻을 수 있습니다.
1 단계 : 주제는이를위한 방법을 중심으로 진행되므로 Mybatis부터 시작하겠습니다. 먼저, 우리는 간단한 이해를 위해 mybatis와 관련된 두 가지 더 중요한 구성 파일을 꺼낼 것입니다. 하나는 mybatis-config.xml이고, 다른 하나는 엔티티에 해당하는 Mapper 구성 파일입니다. 구성 파일에 댓글을 작성하고 모든 사람이 한 눈에 이해할 것입니다.
mybatis-config.xml
<! docType configuration public "-// mybatis.org//dtd config 3.0 // en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <! <!-글로벌 매개 변수-> <setings> <!-글로벌 맵퍼를 활성화 또는 디스턴스 클래시를 만듭니다. -> <setting name = "cacheenabled"value = "false"/> <!-전 세계적으로 게으른 하중을 활성화 또는 비활성화합니다. 비활성화되면 모든 관련 객체가 즉시로드됩니다. -> <setting name = "lazyloadingEnabled"value = "true"/> <!-활성화되면 게으른 로딩 속성이있는 객체가 호출 될 때 속성을 완전히로드합니다. 그렇지 않으면 각 속성은 필요에 따라로드됩니다. -> <setting name = "AttressivelaZyloading"value = "true"/> <!-단일 SQL이 여러 데이터 세트를 반환 할 수 있는지 여부 (드라이버의 호환성에 따라) 기본값 : true-> < "multiplerestestSetSenabled"value = "true"/<!-열에 대한 별명이 사용될 수 있는지 여부 (true) name = "usecolumnlabel"value = "true"/> <!- JDBC가 기본 키를 생성하도록 허용합니다. 드라이브 지원이 필요합니다. True로 설정되면이 설정은 생성 된 기본 키를 강제로 강제로, 일부 드라이브는 양립 할 수 없지만 여전히 실행할 수 있습니다. 기본값 : false-> <setting name = "usegeneratedKeys"value = "false"/> <!-MyBatis가 데이터베이스 테이블의 열을 자동으로 매핑하는 방법을 지정하십시오 : 부분 전체 : all glog : all at emperat : "autupapping behavior"value = "파트너"/> <!-이것은 기본 실행 유형입니다. 명령문 및 배치 업데이트)-> <설정 이름 = "defaultexecutortype"value = "simple"/> <!-낙타 명명법을 사용하여 필드를 변환합니다. -> <seting name = "mapUnderscoretocamelcase"value = "true"/> <!-로컬 캐시 범위 세션 설정 : 데이터 공유 명령문이 있습니다 : 문장 범위 (이것은 데이터 공유가 아님) defalut : session = "value ="session "/> <!-jdbc 유형이 비어 있지 않으며, 일부 드라이버는 가치를 지정해야합니다. null 값을 삽입 할 때 유형-> <setting name = "jdbctypefornull"value = "null"/> <setting name = "logprefix"value = "dao."/> </settings> <!-별칭은 짧은 Java 유형의 이름입니다-> <tontealias> <faintealias type = "com.store.base.model.storeuer" alias = "user"> </inftealias> <faintealias type = "com.store.base.secondmodel.pratice.model.product"alias = "product"> </infinealias> <faintealias type = "com.store.base.base.secondmodel.base.page"alias = "page"> </typealias> </typealias> </typealias> </typealias> MyBatis 용으로 구성된 페이지 인터셉터는이 페이지 인터셉터를 구현해야합니다 -> <플러그인> <플러그인 인터셉터 = "com.store.base.secondmodel.base.pageinterceptor.paginationinterceptor"/> </plugins> </configuration>
ProductMapper.xml은 테스트 객체로 사용 되며이 Mapper 파일은 사용해야하는 쿼리 문을 구성합니다.
<? xml version = "1.0"encoding = "utf-8"?> <! doctype mapper public "-// mybatis.org//dtd Mapper 3.0 // en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> namespace = "com.store.base.secondmodel.pratice.dao.productdao"> <sql id = "basecolumns"> id, product_name, productName, product_no, productNo, 가격 </sql> < "findlist"를 선택하십시오. resulttype = "com.store.base.secondmodel.pratice.model.product"> t_store_product </select> </mapper>의 refid = "basecolumns"/> 포함
2 단계 : 다음으로, 우리는 주로 다음 클래스와 해당 인터페이스를 포함 하여이 페이지 매김 인터셉터에 대한 심층 분석 및 학습을 수행합니다.
(1) Baseinterceptor 인터셉터 기본 클래스
(2) Pagination Interceptor 우리가 사용하려는 Pagination 플러그인 클래스, 위의 기본 클래스를 상속받습니다.
(3) SQLHELPER는 주로 카운트 명령문을 미리 실행하고 전체 완전한 페이지 매김 문을 얻는 데 사용됩니다.
(4) 방언, mysqldialect는 주로 데이터베이스가 한계 명령문을 지원 한 다음 전체 제한 문을 캡슐화하는 데 사용됩니다.
다음은 이러한 범주의 공유 디스플레이입니다
Baseinterceptor.java
package com.store.base.secondmodel.base.pageinterceptor; java.io.serializable import; java.util.properties import; import org.apache.ibatis.logging.log; import org.apache.ibatis.logging.logfactory; org.apache.ibatis.plugin.interceptor import; com.store.base.secondmodel.base.global import; com.store.base.secondmodel.base.page import; com.store.base.secondmodel.base.dialect.dialect import; com.store.base.secondmodel.base.dialect.mysqldialect import; com.store.base.util.reflections import; / ** * MyBatis Pagination Interceptor Base Class * @author yiyong_wu */ public Abstract Class Baseinterceptor는 인터셉터, 직렬화 가능한 {private static final long serialversionuid = 1L; 보호 된 정적 최종 문자열 페이지 = "페이지"; 보호 된 정적 최종 문자열 delegate = "Delegate"; 보호 된 정적 최종 문자열 mapped_statement = "MappedStatement"; 보호 로그 로그 = logfactory.getLog (this.getClass ()); 보호 된 방언 방언; / *** 매개 변수를 변환 및 점검* @param parameterObject ParameterObject ParameterObject* @Param Page Pagination Object* @return Paginceation Object* @throws NosuchfieldException 매개 변수*/ @SuppressWarnings ( "Checked Unchecked") 보호 된 정적 페이지 <botort> convertParameter (객체 {Object> Page) {PARAMETEROTOTOP) (page <bood>) ParameterObject; } else {return (page <bood>) reclections.getFieldValue (parameterObject, page); }} catch (예외 e) {return null; }} /*** 속성 설정, 사용자 정의 방언 클래스 및 데이터베이스를 공식화하는 방법* <code> DialectClass < /code>, 사용자 정의 방언 클래스. * <ode> dbms </ode> 데이터베이스 유형, 플러그인 * <code> sqlpattern </code> sql id */protected void initproperties (properties p) {nullect = null; 문자열 dbtype = global.getConfig ( "jdbc.type"); if ( "mysql".equals (dbtype)) {delect = new mysqldialect (); } if (dalect == null) {throw new runtimeexception ( "mybatis dialect error."); } dialect = 방언; }}Pagination Interceptor.java
package com.store.base.secondmodel.base.pageinterceptor; java.util.properties import; import org.apache.ibatis.executor.executor; import org.apache.ibatis.mapping.boundsql; import org.apache.ibatis.mapping.mappedstatement; import org.apache.ibatis.mapping.sqlsource; import org.apache.ibatis.plugin.intercepts; import org.apache.ibatis.plugin.invocation; import org.apache.ibatis.plugin; import org.apache.ibatis.plugin.signature; import org.apache.ibatis.reflection.metaobject; import org.apache.ibatis.session.resulthandler; import org.apache.ibatis.session.rowbounds; com.store.base.secondmodel.base.page import; com.store.base.secondmodel.base.util.stringutils import; com.store.base.util.reflections import; /*** 데이터베이스 페이징 플러그인은 쿼리 문을 가로 채 웁니다. * @Author yiyong_wu * */ @intercepts ({@Signature (type = executor.class, method = "query", args = {mappedStatement.class, object.class, rowbounds.class, resulthandler.class.class}))) public class paginationinterceptor {private long serial intercertor v; @override public object intercept (호출 호출) 던지기 가능 {최종 매핑 스테이트 매핑 스테이트 = (MappedStatement) invocation.getargs () [0]; 객체 매개 변수 = invocation.getargs () [1]; BONDSQL BONDSQL = MAPPEDSTATEMENT.GETBOUNDSQL (매개 변수); Object ParameterObject = boundsql.getParameterObject (); // Pagination 매개 변수 객체 페이지 페이지 <bood> page = null; if (parameterObject! = null) {page = convertParameter (parameterObject, page); } // 페이징 객체가 설정되면 PAGIGE가 수행됩니다. } string onstayalSql = boundsql.getSql (). trim (); // 총 레코드 수를 가져옵니다. // Pagination Query 현지화 된 객체를위한 데이터베이스를 수정하고 구현 문자열 수정에주의를 기울여야합니다. pagesql = sqlhelper.generatepagesql (Originalalsql, Page, Dialect); invocation.getArgs () [2] = new rowbounds (rowbounds.no_row_offset, rowbounds.no_row_limit); BONDSQL NEWBOUNDSQL = NEW BONDSQL (MAPPEDSTATEMENT.GETCONFIGURATION (), PAGESQL, BONDSQL.GETPARAMETERMAPPINGS (), BONDSQL.GETPARAMETEROBJECT ()); // If (reclections.getFieldValue ( "metaparameters")! = null) {metaobject mo = (metaobject) Reflections.getFieldValue (boundSql, "metaparameters"); 반사시 .setfieldValue (NewboundSQL, "Metaparameters", MO); } // 지식 매개 변수에 대한 myBatis 페이지 매개 변수 실패 끝 mappedstatement newms = CopyFrommappedStatement (MappedStatement, New BoundSQLSQLSource (NewboundSQL)); invocation.getargs () [0] = newms; } return invocation.ProCeed (); } @override public Object Plugin (개체 대상) {return plugin.wrap (target, this); } @override public void setProperties (속성 속성) {super.initproperties (속성); } private MappedStatement CopyFrommappedStatement (MappedStatement MS, SQLSource NewsQLSource) {MappedStatement.Builder Builder = New MappedStatement.Builder (Ms.GetConfiguration (), Ms.GetID (), NewsQlSource, Ms.GetSQLCMANMTYPE (); builder.resource (ms.getResource ()); builder.fetchsize (ms.getfetchsize ()); builder.statementtype (ms.getStatementType ()); builder.keygenerator (ms.getKeyGenerator ()); if (ms.getKeyProperTies ()! = null) {for (String keyProperty : Ms.GetKeyProperTies ()) {builder.keyProperty (keyProperty); }} builder.timeout (ms.gettimeout ()); builder.parametermap (ms.getparametermap ()); builder.resultMaps (ms.getResultMaps ()); builder.cache (ms.getCache ()); return builder.build (); } public static class boundsqlsqlsource는 sqlsource {boundsql boundsql; public boundsqlsqlsource (boundsql boundsql) {this.boundsql = boundsql; } @override public boundsql getBoundsql (Object ParameterObject) {return boundsql; }}}sqlhelper.java
package com.store.base.secondmodel.base.pageinterceptor; java.sql.connection 가져 오기; Java.sql.preparedStatement import; java.sql.resultset import; java.sql.sqlexception 가져 오기; Java.util.list 가져 오기; import java.util.regex.matcher; java.util.regex.pattern import; import org.apache.ibatis.executor.errorcontext; import org.apache.ibatis.executor.executorexception; import org.apache.ibatis.logging.log; import org.apache.ibatis.mapping.boundsql; import org.apache.ibatis.mapping.mappedstatement; import org.apache.ibatis.mapping.parametermpapping; import org.apache.ibatis.mapping.parametermode; import org.apache.ibatis.reflection.metaobject; import org.apache.ibatis.reflection.property.propertytokenizer; import org.apache.ibatis.scripting.xmltags.foreachsqlnode; import org.apache.ibatis.session.configuration; import org.apache.ibatis.type.typehandler; import org.apache.ibatis.type.typehandlerregistry; com.store.base.secondmodel.base.global import; com.store.base.secondmodel.base.page import; com.store.base.secondmodel.base.dialect.dialect import; com.store.base.secondmodel.base.util.stringutils import; com.store.base.util.reflections import; /*** SQL 도구 클래스* @Author yiyong_wu** /public class sqlhelper { /*** 기본 개인 생성자* /private sqlhelper () {} /*** sql parameters (?)의 값을 설정합니다. SQL 진술의 대상. * @param mappedstatement mappedstatement * @param boundsql sql * @param parameterobject parameterObeject ParameterObject @throws java.sql.sqlexception 데이터베이스 예외 */ @suppresswarnings ( "Checked") public static void setparameters (준비된 스테이션 PS, MappedStatement MappledStatement, boundStatement maplstatement maplestement ParameterObject)는 sqlexception {errorcontext.instance () activity ( "설정 매개 변수"). 개체 (mappedStatement.getParameterMap (). getId ()); List <ParametErmpaping> ParametErmappings = boundsql.getParameterMappings (); if (parameterMappings! = null) {configuration configuration = mappedStatement.getConfiguration (); TypeHandlerRegistry TypeHandlerRegistry = configuration.getTypeHandlerRegistry (); metaobject metaobject = parameterObject == null? null : configuration.newmetaObject (parameterObject); for (int i = 0; i <parameterMappings.size (); i ++) {ParametErmpapping ParametErmpaping = ParameterMappings.get (i); if (parameterMpapping.getMode ()! = ParametErmode.out) {개체 값; 문자열 propertyname = parameterMpapp.GetProperty (); PropertyTokenizer Prop = New PropertyTokenizer (PropertyName); if (parameterObject == null) {value = null; } else if (typeHandlerRegistry.hastypeHandler (parameterObject.getClass ())) {value = parameterObject; } else if (boundsql.hasadditionalParameter (propertyName)) {value = boundsql.getAdditionalParameter (PropertyName); } else if (propertyname.startSwith (foreachsqlnode.item_prefix) && boundsql.hasadditionalParameter (prop.getname ())) {value = boundsql.getAdditionalParameter (prop.getName ()); if (value! = null) {value = configuration.newmetaObject (value) .getValue (propertyName.SubString (prop.getName (). longth ())); }} else {value = metaobject == null? null : metaobject.getValue (PropertyName); } @SuppressWarnings ( "rawTypes") TypeHandler TypeHandler = ParametErmpapp.GetTypeHandler (); if (typehandler == null) {Throw new executeRexception ( "매개 변수에 대한 유형 핸들러가 없음" + propertyName + "명령문" + mappedStatement.getId ()); } typeHandler.setParameter (ps, i + 1, 값, parameterMpapp.getJdbCtype ()); }}}} / *** 쿼리 총 레코드* @param sql sql state* @param 연결 데이터베이스 연결* @param mapppedstatement mapping* @param parameterobject 매개 변수* @param boundsql boundsql* @return 총 레코드 수* @throws sqlexcection sql query error* / public static int gettatic count MappedStatement, 최종 오브젝트 파라미터 로버, 최종 BoundSQL BoundSQL, Log Log) SQLEXCEPTion {String DBNAME = global.getConfig ( "jdbc.type"); 최종 문자열 countsql; if ( "oracle".equals (dbname)) {countsql = "count (1)에서 (" + sql + ") tmp_count"; } else {countsql = "(" + remodorders (sql) + ") tmp_count"에서 count (1)를 선택하십시오. "; } 연결 연결 = 연결; 준비된 상태 ps = null; resultSet rs = null; try (log.isdebugenabled ()) {log.debug ( "count sql :" + stringutils.replaceeach (countsql, new String [] { "/n", "/t"}, new String [] { "", "}); } if (conn == null) {conn = mappedStatement.getConfiguration (). getEnvironment (). getDatasource (). getConnection (); } ps = conn.preparestatement (countsql); BONDSQL COUNTBS = NEW BONDSQL (MAPPEDSTATEMENT.GETCONFIGURATION (), COUNTSQL, BONDSQL.GETPARAMETERMAPPINGS (), PARAMERTEBERMER); // If (reclections.getFieldValue ( "metaparameters")! = null) {metaobject mo = (metaobject) Reflections.getFieldValue (boundSql, "metaparameters"); 반사 .setfieldValue (Countbs, "Metaparameters", MO); } // 지식 매개 변수에 대한 myBatis 페이지 매개 변수 실패 END SQLHELPER.SETPARAMETERS (PS, MAPPEDSTATEMENT, COUNTBS, PARALETEROBJECT); rs = ps.ExecuteQuery (); int count = 0; if (rs.next ()) {count = rs.getint (1); } 반환 수; } 마침내 {if (rs! = null) {rs.close (); } if (ps! = null) {ps.close (); } if (conn! = null) {conn.close (); }}} / *** 데이터베이스 방언에 따라 특정 페이지 생성* @param sql mapper* @param page object* @param dialect dialect type* @return paging sql* / public static string generatepagesql (page <boter> page, page, delect delect) {delect.support.support.support.support. decient.getLimitstring (sql, page.getfirstresult (), page.getMaxResults ()); } else {return sql; }} /*** qlstring의 선택 절을 제거합니다. * @param hql * @return */ @suppresswarnings ( "Unused") private static string removeSelect (String qlString) {int stegtstring.tolowercase (). indexof ( "from"); qlstring.substring (betterpos)을 반환합니다. } /*** HQL의 Orderby 절을 제거합니다. *@param hql *@return */private static string remakorders (String qlstring) {pattern p = pattern.compile ( "Order // s *by [// w | // w | // s | // s] *", pattern.case_insensive); 매치 자 m = p.matcher (Qlstring); StringBuffer sb = new StringBuffer (); while (m.find ()) {M.appendReplacement (sb, ""); } M.Appendtail (SB); 반환 sb.toString (); }}divelect.java 인터페이스
package com.store.base.secondmodel.base.dialect; / *** 최대 절전 모드와 유사하지만 페이징 부분 만 단순화됩니다* @Author yiyong_wu*/ public 인터페이스 방언 {/ *** 데이터베이스 자체는 페이징에 대한 현재 페이징 쿼리 메소드를 지원합니까* 데이터베이스가 그것을 지원하지 않는 경우, 데이터베이스 페이징은 PAGIGE* @Return true를 지원하지 않을 것입니다. / ** * SQL을 Pagination SQL로 변환하고 통화 페이징 SQL을 별도로 변환 * * @Param SQL SQL 문 * @Param 오프셋 시작 번호 * @Param 제한 페이지 당 표시되는 레코드 수 * 페이지 매출 쿼리 */ public string getLimitstring (String SQL, int thegset, int 제한); }mysqldialect.java
package com.store.base.secondmodel.base.dialect; / ** * MySQL 방언 구현 * @Author yiyong_wu */ public class mysqldialect emperments dialct {@override public boolean supportlimit () {return true; } @override public string getLimitstring (String SQL, int Offset, int Limit) {return getLimitstring (SQL, 오프셋, integer.toString (오프셋), integer.toString (Limit)); } /*** SQL을 PAGED SQL 문으로 전환하여 오프셋 및 제한을 자리 표시 자와 대체합니다. 예를 들어, mysql * decient.getlimitstring ( "선택 *에서 선택 * 선택 *", 12, ": 오프셋", 0, ": Limit"는 * 선택 * 선택 *에서 * </pre> * * * @param sql 문 * @param 오프셋 오프셋 주택 hatination 숫자 * @param pagpplace hall hall hall haln @return Pagination SQL 자리 표시자가 포함되어 */ public String getLimitstring (문자열 SQL, int 오프셋, 문자열 오프셋 플레이어 홀더, String LimitPlaceHolder) {StringBuilder StringBuilder = new StringBuilder (SQL); StringBuilder.Append ( "Limit"); if (offset> 0) {StringBuilder.append (OffsetPlaceHolder) .append ( ","). Append (LimitPlaceHolder); } else {StringBuilder.Append (LIMITPLATERALDER); } return stringBuilder.toString (); }}거의 여기에 전체 페이지를 구현하는 방법을 공유했지만 더 중요한 작업이 있습니다. 우리가 모든 것이 실행되기를 원한다면, 우리는 할 일이 있어야합니다. 다음으로, 우리는 전체 페이지 객체 세트와 3 계층 아키텍처를 기반으로하는 3 층 아키텍처를 분석하고 제품을 분석을위한 엔티티로 사용합니다. 완전한 3 층 아키텍처에 대해 이야기 한 후에는 보상이 확실히 가득합니다. 엔티티-> dao-> 서비스의 순서대로 그것에 대해 이야기합시다.
먼저, 우리는 두 개의 추상 엔티티 클래스 기업에 대한 데이터 엔티티와 데이터 엔티티를 상속해야합니다.
baseentity.java 주로 페이지 멤버 변수를 배치합니다. 상속 후, 각 엔티티는이 멤버 변수를 가질 수 있습니다.
package com.store.base.secondmodel.base; java.io.serializable import; java.util.map import; javax.xml.bind.annotation.xmltransient import; import org.apache.commons.lang3.stringutils; import org.apache.commons.lang3.builder.reflectionToStringBuilder; import com.fasterxml.jackson.annotation.jsonignore; import com.google.common.collect.maps; com.store.base.model.storeuser import; / ** * 최상위 엔티티 * @Author yiyong_wu * * @param <t> */ public acpract class baseentity <t> 시리얼 리화 가능 {private static final long serialversionuid = 1L; / ** * 태그 삭제 (0 : normal; 1 : delete; 2 : audit;) */ public static final String del_flag_normal = "0"; 공개 정적 최종 문자열 del_flag_delete = "1"; 공개 정적 최종 문자열 del_flag_audit = "2"; / *** 엔티티 번호 (고유 식별자)*/ 보호 된 문자열 ID; / *** 현재 사용자*/ Protected StoreUser currentUser; / *** 현재 엔티티 페이지 매김 객체*/ 보호 페이지 <T> 페이지; / ** * Custom SQL (SQL 식별자, SQL 컨텐츠) */ 개인지도 <String, String> SQLMAP; Public Baseentity () {} public baseentity (String id) {this (); this.id = id; } public String getId () {return id; } public void setId (String id) {this.id = id; } / *** 이것은 Shiro가 현재 사용자에게 삽입 업데이트를 수행 할 때 호출됩니다. } currentUser를 반환합니다. } public void setCurrentUser (StoreUser currentUser) {this.currentUser = currentUser; } @jsonignore @xmltransient public page <t> getPage () {if (page == null) {page = new Page <> (); } 반환 페이지; } public page <T> setPage (page <t> page) {this.page = page; 반환 페이지; } @jsonignore @xmltransient public map <string, string> getSqlmap () {if (sqlmap == null) {sqlmap = maps.newhashmap (); } 반환 sqlmap; } public void setsqlmap (map <string, string> sqlmap) {this.sqlmap = sqlmap; } / ** * 삽입 전에 메소드를 실행, 서브 클래스 구현 * / public acpract void preinsert (); / ** * 업데이트 전에 메소드를 실행합니다. 서브 클래스 구현 */ public acpract void preupdate (); /*** 새 레코드 (기본값 : false) 여부에 관계없이 setisNewRecord ()를 호출하여 새 레코드를 설정하고 사용자 정의 ID를 사용하십시오. * true로 설정 한 후 삽입 문을 실행해야합니다. ID는 자동으로 생성되지 않으며 수동으로 전달해야합니다. * @return */ public boolean getisnewrecord () {return stringUtils.isblank (getId ()); } / *** 글로벌 변수 객체* / @jsonignore public global getGlobal () {return global.getInstance (); } / *** 데이터베이스 이름 가져 오기* / @jsonignore public string getDbname () {return global.getConfig ( "jdbc.type"); } @override public String toString () {return ReflectionToStringBuilder.toString (this); }}DataEntity.java, 주로 시간 업데이트 및 삭제, 사용자 만들기, 사용자 업데이트, 논리 삭제 플래그 등을 저장합니다.
package com.store.base.secondmodel.base; import java.util.date; org.hibernate.validator.constraints.length; import com.fasterxml.jackson.annotation.jsonformat; import com.fasterxml.jackson.annotation.jsonignore; com.store.base.model.storeuser import; / ** * 데이터 엔티티 * @Author yiyong_wu * * @param <t> */ public acpract class dataentity <t> baseentity <t> {private static final long serialversionuid = 1l; 보호 된 저장고 CreateBy; // Creator Protected Date Creadate; // 생성 날짜 보호 저장소 업데이트; // 업데이트 보호 날짜 업데이트; // 업데이트 된 날짜 보호 문자열 delflag; // 태그 삭제 (0 : normal; 1 : delete; 2 : audit) public dataentity () {super (); this.delflag = del_flag_normal; } public dataentity (String ID) {super (id); } / ** * 삽입하기 전에 메소드를 실행하려면 * / @override public void preinsert () {// id에서 id로 제한이없고 setisNewRecord ()를 호출하려면 사용자 정의 ID // user user user.getUser (); // if (stringUtils.isnotBlank (user.getId ()) {// this.updateby = user; // this.createby = 사용자; //} this.updatedate = new Date (); this.createdate = this.updateate; } / ** * 업데이트 전에 메소드를 실행하려면 * / @override public void preupdate () {// user user = userutils.getUser (); // if (stringUtils.isnotBlank (user.getId ()) {// this.updateby = user; //} this.updatedate = new Date (); } // @jsonignore Public StoreUser getCreateBy () {return CreateBy; } public void setcreateby (StoreUser CreateBy) {this.createby = CreateBy; } @jsonformat (pattern = "yyyy-mm-dd hh : mm : ss") 공개 날짜 getCreatedate () {return readate; } public void setCreatedate (날짜 createate) {this.createdate = createate; } // @jsonignore Public StoreUser getUpdateby () {return updateby; } public void setupdateby (StoreUser UpdateBy) {this.updateby = updateby; } @jsonformat (pattern = "yyyy-mm-dd hh : mm : ss") 공개 날짜 getUpdatedate () {return updatedate; } public void setupdatedate (날짜 업데이트) {this.updatedate = 업데이트; } @jsonignore @length (min = 1, max = 1) public String getDelflag () {return delflag; } public void setDelflag (String delflag) {this.delflag = delflag; }}제품. 자바 제품 카테고리
package com.store.base.secondmodel.pratice.model; com.store.base.secondmodel.base.dataentity import; / ***제품 기본 수업*2016 년 10 월 11 일*Yiyong_wu*/ public class 제품 확장 데이터 엔티티 <Product> {개인 정적 최종 최종 SerialVersionUid = 1L; 개인 문자열 productName; 개인 플로트 가격; 개인 문자열 productno; 공개 문자열 getProductName () {return productName; } public void setProductName (String ProductName) {this.productName = productName; } public float getPrice () {리턴 가격; } public void setPrice (플로트 가격) {this.price = 가격; } public String getProductNo () {return productNo; } public void setProductno (String ProductNo) {this.productno = productNo; }}어때? 매우 복잡한 실체 상속 관계가 보이나요? 그러나 무엇이 있습니까? 더 복잡할수록 더 완전 할 것입니다. 다음으로 나는 침례를받을 준비가 된 층, 같은 세 층을 보게 될 것입니다.
Rasedao.java 예약 인터페이스
package com.store.base.secondmodel.base; / ** * 가장 큰 DAO 인터페이스 * @Author yiyong_wu * */ public interface basedao {} cruddao.java 추가, 삭제, 수정 및 쿼리 [Java] 일반 사본 인쇄를위한 DAO 인터페이스 레이어? 내 코드 조각에서 파생 된 코드 조각에서 코드 조각을보기 Com.store.base.secondmodel.base; Java.util.list 가져 오기; / ** * 추가, 삭제, 수정 및 쿼리를 위해 DAO 인터페이스 정의 * @author yiyong_wu * * @param <t> */ public interface cruddao <t> 확장 기반 데이터 {/ ** * 단일 데이터를 얻습니다 * @param id * @return */ public t get (string id); / ** * 단일 데이터를 얻습니다 * @param 엔티티 * @return */ public t get (t entity); /*** 데이터 목록을 쿼리합니다. 페이징이 필요한 경우 : Entity.setPage (새 페이지 <T> ()); * @Param Entity * @return */ public list <T> FindList (T Entity); / ** * 모든 데이터 목록 쿼리 * @param entity * @return */ public list <T> findAllList (t entity); /*** 모든 데이터 목록 쿼리* @ @findAllList (t entity)* @return public list <T> findAllList (); *// ** * 데이터 삽입 * @param 엔티티 * @return */ public int insert (t entity); / ** * 데이터 업데이트 * @param entity * @return */ public int update (t entity); / ** * 데이터 삭제 (일반적으로 논리적 삭제, del_flag 필드를 1) * @param id * @see public int delete (t entity) * @return */ public int delete (String id); / ** * 데이터 삭제 (일반적으로 논리적 삭제, del_flag 필드를 1) * @param entity * @return */ public int delete (t entity); }ProductDao.java MyBatis 해당 인터페이스 맵퍼도 DAO 구현입니다. 주석 @mybatisRepository를 사용자 정의해야합니다
package com.store.base.secondmodel.pratice.dao; com.store.base.secondmodel.base.cruddao import; com.store.base.secondmodel.base.mybatisrepository import; com.store.base.secondmodel.pratice.model.product import; / ** *TODO *2016 년 10 월 11 일 *yiyong_wu */ @MyBatisRepository public interface productdao 확장 cruddao <product> {}맞춤 주석 MyBatisRepository.java는 사용자 정의 주석과 관련이 있습니다. 나는 여기에 너무 많이 설명하지 않을 것이며 온라인 정보가 많이 있습니다.
package com.store.base.secondmodel.base; import java.lang.annotation.documented; java.lang.annotation.trention import; Java.lang.annotation.target import; java.lang.annotation.retentionpolicy import; import java.lang.annotation.elementtype; org.springframework.stereotyp.component import; /*** {@link org.mybatis.spring.mapper.mapperscannerconfigurer}의 스캔을 용이하게하기 위해 mybatis의 dao를 식별합니다. * *스프링 구성 파일에서 주석이 붙은 클래스를 스캔하도록 구성하려는 구성을 구성하려는 경우 * *<bean id = "mapperscannerConfigurer"> *<속성 이름 = "sqlsessionFactoryBeanName"value = "sqlsession actory" /> *<property name = "value"value = "com.store.base.base.secondmodel. 이름 = "AnnotationClass"value = "com.store.base.secondmodel.base.mybatisRepository"/> * </bean> * @author yiyong_wu * */@retention (resentionpolicy.runtime) @target (expertype.type) @documented public @intersereporitory mybatipitority mybat value value "";; } 참고 : ProductDao.java와 강력한 연결이있는 ProductMapper.xml 파일은 ProductMapper.xml 파일입니다. 위의 구성 파일의 네임 스페이스 가이 DAO의 경로를 가리 킵니다.
다음으로 우리는 최종 서비스 분석에 들어가며 3 층 상속입니다.
BaseService.java
package com.store.base.secondmodel.base; import org.slf4j.logger; org.slf4j.loggerfactory; org.slf4j.loggerfactory; org.springframework.transaction.annotation.transactional import; / ** * 최상위 수준의 부모 서비스 클래스 * @Author yiyong_wu */ @transactional (readonly = true) public acpract class baseService {// protected logger = loggerfactory.getLogger (getClass ()); }Crudservice.java 관련 비즈니스 인터페이스 구현
package com.store.base.secondmodel.base; Java.util.list 가져 오기; org.springframework.beans.factory.annotation.autowired; org.springframework.transaction.annotation.transactional import; / ** * 서비스베이스 클래스를 추가, 삭제, 수정 및 확인하고 확인하십시오. @author yiyong_wu * * @param <d> * @param <t> */ public acpract class crudservice <d extends cruddao <t>, t extends datendity <t >> 기본 서비스 {/ ** * irestence object */ @afired d dao; / ** * 단일 데이터를 가져옵니다 * @param id * @return */ public t get (string id) {return dao.get (id); } / ** * 단일 데이터를 가져옵니다 * @param entity * @return * / public t get (t entity) {return dao.get (엔티티); } /** * Query list data* @param entity * @return */ public List<T> findList(T entity) { return dao.findList(entity); } /** * Query paging data* @param page paging object* @param entity * @return */ public Page<T> findPage(Page<T> page, T entity) { entity.setPage(page); page.setList(dao.findList(entity)); return page; } /** * Save data (insert or update) * @param entity */ @Transactional(readOnly = false) public void save(T entity) { if (entity.getIsNewRecord()){ entity.preInsert(); dao.insert(entity); }else{ entity.preUpdate(); dao.update(entity); } } /** * Delete data* @param entity */ @Transactional(readOnly = false) public void delete(T entity) { dao.delete(entity); }}ProductService.java,去继承CrudService接口,注意起注入dao和实体类型的一种模式
package com.store.base.secondmodel.pratice.service; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.store.base.secondmodel.base.CrudService; import com.store.base.secondmodel.pratice.dao.ProductDao; import com.store.base.secondmodel.pratice.model.Product; /** *TODO *2016年10月11日*yiyong_wu */ @Service @Transactional(readOnly = true) public class ProductService extends CrudService<ProductDao,Product>{ }我想看到这里的同志已经很不耐烦了。但是如果你错过接下去的一段,基本上刚才看的就快等于白看了,革命的胜利就在后半段,因为整个分页功能围绕的就是一个Page对象,重磅内容终于要出来了,当你把Page对象填充到刚才那个BaseEntity上的时候,你会发现一切就完整起来了,废话不多说,Page对象如下
package com.store.base.secondmodel.base; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.fasterxml.jackson.annotation.JsonIgnore; import com.store.base.secondmodel.base.util.CookieUtils; import com.store.base.secondmodel.base.util.StringUtils; /** * 分页类* @author yiyong_wu * * @param <T> */ public class Page<T> implements Serializable{ private static final long serialVersionUID = 1L; private int pageNo = 1; // 当前页码private int pageSize = Integer.parseInt(Global.getConfig("page.pageSize")); // 页面大小,设置为“-1”表示不进行分页(分页无效) private long count;// 总记录数,设置为“-1”表示不查询总数private int first;// 首页索引private int last;// 尾页索引private int prev;// 上一页索引private int next;// 下一页索引private boolean firstPage;//是否是第一页private boolean lastPage;//是否是最后一页private int length = 6;// 显示页面长度private int slider = 1;// 前后显示页面长度private List<T> list = new ArrayList<>(); private String orderBy = ""; // 标准查询有效, 实例: updatedate desc, name asc private String funcName = "page"; // 设置点击页码调用的js函数名称,默认为page,在一页有多个分页对象时使用。 private String funcParam = ""; // 函数的附加参数,第三个参数值。 private String message = ""; // 设置提示消息,显示在“共n条”之后public Page() { this.pageSize = -1; } /** * 构造方法* @param request 传递repage 参数,来记住页码* @param response 用于设置Cookie,记住页码*/ public Page(HttpServletRequest request, HttpServletResponse response){ this(request, response, -2); } /** * 构造方法* @param request 传递repage 参数,来记住页码* @param response 用于设置Cookie,记住页码* @param defaultPageSize 默认分页大小,如果传递-1 则为不分页,返回所有数据*/ public Page(HttpServletRequest request, HttpServletResponse response, int defaultPageSize){ // 设置页码参数(传递repage参数,来记住页码) String no = request.getParameter("pageNo"); if (StringUtils.isNumeric(no)){ CookieUtils.setCookie(response, "pageNo", no); this.setPageNo(Integer.parseInt(no)); }else if (request.getParameter("repage")!=null){ no = CookieUtils.getCookie(request, "pageNo"); if (StringUtils.isNumeric(no)){ this.setPageNo(Integer.parseInt(no)); } } // 设置页面大小参数(传递repage参数,来记住页码大小) String size = request.getParameter("pageSize"); if (StringUtils.isNumeric(size)){ CookieUtils.setCookie(response, "pageSize", size); this.setPageSize(Integer.parseInt(size)); }else if (request.getParameter("repage")!=null){ no = CookieUtils.getCookie(request, "pageSize"); if (StringUtils.isNumeric(size)){ this.setPageSize(Integer.parseInt(size)); } }else if (defaultPageSize != -2){ this.pageSize = defaultPageSize; } // 设置排序参数String orderBy = request.getParameter("orderBy"); if (StringUtils.isNotBlank(orderBy)){ this.setOrderBy(orderBy); } } /** * 构造方法* @param pageNo 当前页码* @param pageSize 分页大小*/ public Page(int pageNo, int pageSize) { this(pageNo, pageSize, 0); } /** * 构造方法* @param pageNo 当前页码* @param pageSize 分页大小* @param count 数据条数*/ public Page(int pageNo, int pageSize, long count) { this(pageNo, pageSize, count, new ArrayList<T>()); } /** * 构造方法* @param pageNo 当前页码* @param pageSize 分页大小* @param count 数据条数* @param list 本页数据对象列表*/ public Page(int pageNo, int pageSize, long count, List<T> list) { this.setCount(count); this.setPageNo(pageNo); this.pageSize = pageSize; this.list = list; } /** * 初始化参数*/ public void initialize(){ //1 this.first = 1; this.last = (int)(count / (this.pageSize < 1 ? 20 : this.pageSize) + first - 1); if (this.count % this.pageSize != 0 || this.last == 0) { this.last++; } if (this.last < this.first) { this.last = this.first; } if (this.pageNo <= 1) { this.pageNo = this.first; this.firstPage=true; } if (this.pageNo >= this.last) { this.pageNo = this.last; this.lastPage=true; } if (this.pageNo < this.last - 1) { this.next = this.pageNo + 1; } else { this.next = this.last; } if (this.pageNo > 1) { this.prev = this.pageNo - 1; } else { this.prev = this.first; } //2 if (this.pageNo < this.first) {// 如果当前页小于首页this.pageNo = this.first; } if (this.pageNo > this.last) {// 如果当前页大于尾页this.pageNo = this.last; } } /** * 默认输出当前分页标签* <div>${page}</div> */ @Override public String toString() { StringBuilder sb = new StringBuilder(); if (pageNo == first) {// 如果是首页sb.append("<li class=/"disabled/"><a href=/"javascript:/">« 上一页</a></li>/n"); } else { sb.append("<li><a href=/"javascript:/" onclick=/""+funcName+"("+prev+","+pageSize+",'"+funcParam+"');/">« 上一页</a></li>/n"); } int begin = pageNo - (length / 2); if (begin < first) { begin = first; } int end = begin + length - 1; if (end >= last) { end = last; begin = end - length + 1; if (begin < first) { begin = first; } } if (begin > first) { int i = 0; for (i = first; i < first + slider && i < begin; i++) { sb.append("<li><a href=/"javascript:/" onclick=/""+funcName+"("+i+","+pageSize+",'"+funcParam+"');/">" + (i + 1 - first) + "</a></li>/n"); } if (i < begin) { sb.append("<li class=/"disabled/"><a href=/"javascript:/">...</a></li>/n"); } } for (int i = begin; i <= end; i++) { if (i == pageNo) { sb.append("<li class=/"active/"><a href=/"javascript:/">" + (i + 1 - first) + "</a></li>/n"); } else { sb.append("<li><a href=/"javascript:/" onclick=/""+funcName+"("+i+","+pageSize+",'"+funcParam+"');/">" + (i + 1 - first) + "</a></li>/n"); } } if (last - end > slider) { sb.append("<li class=/"disabled/"><a href=/"javascript:/">...</a></li>/n"); end = last - slider; } for (int i = end + 1; i <= last; i++) { sb.append("<li><a href=/"javascript:/" onclick=/""+funcName+"("+i+","+pageSize+",'"+funcParam+"');/">" + (i + 1 - first) + "</a></li>/n"); } if (pageNo == last) { sb.append("<li class=/"disabled/"><a href=/"javascript:/">下一页»</a></li>/n"); } else { sb.append("<li><a href=/"javascript:/" onclick=/""+funcName+"("+next+","+pageSize+",'"+funcParam+"');/">" + "下一页»</a></li>/n"); } return sb.toString(); } /** * 获取分页HTML代码* @return */ public String getHtml(){ return toString(); } /** * 获取设置总数* @return */ public long getCount() { return count; } /** * 设置数据总数* @param count */ public void setCount(long count) { this.count = count; if (pageSize >= count){ pageNo = 1; } } /** * 获取当前页码* @return */ public int getPageNo() { return pageNo; } /** * 设置当前页码* @param pageNo */ public void setPageNo(int pageNo) { this.pageNo = pageNo; } /** * 获取页面大小* @return */ public int getPageSize() { return pageSize; } /** * 设置页面大小(最大500)// > 500 ? 500 : pageSize; * @param pageSize */ public void setPageSize(int pageSize) { this.pageSize = pageSize <= 0 ? 10 : pageSize; } /** * 首页索引* @return */ @JsonIgnore public int getFirst() { return first; } /** * 尾页索引* @return */ @JsonIgnore public int getLast() { return last; } /** * 获取页面总数* @return getLast(); */ @JsonIgnore public int getTotalPage() { return getLast(); } /** * 是否为第一页* @return */ @JsonIgnore public boolean isFirstPage() { return firstPage; } /** * 是否为最后一页* @return */ @JsonIgnore public boolean isLastPage() { return lastPage; } /** * 上一页索引值* @return */ @JsonIgnore public int getPrev() { if (isFirstPage()) { return pageNo; } else { return pageNo - 1; } } /** * 下一页索引值* @return */ @JsonIgnore public int getNext() { if (isLastPage()) { return pageNo; } else { return pageNo + 1; } } /** * 获取本页数据对象列表* @return List<T> */ public List<T> getList() { return list; } /** * 设置本页数据对象列表* @param list */ public Page<T> setList(List<T> list) { this.list = list; initialize(); return this; } /** * 获取查询排序字符串* @return */ @JsonIgnore public String getOrderBy() { // SQL过滤,防止注入String reg = "(?:')|(?:--)|(///*(?:.|[//n//r])*?//*/)|" + "(//b(select|update|and|or|delete|insert|trancate|char|into|substr|ascii|declare|exec|count|master|into|drop|execute)//b)"; Pattern sqlPattern = Pattern.compile(reg, Pattern.CASE_INSENSITIVE); if (sqlPattern.matcher(orderBy).find()) { return ""; } return orderBy; } /** * 设置查询排序,标准查询有效, 实例: updatedate desc, name asc */ public void setOrderBy(String orderBy) { this.orderBy = orderBy; } /** * 获取点击页码调用的js函数名称* function ${page.funcName}(pageNo){location="${ctx}/list-${category.id}${urlSuffix}?pageNo="+i;} * @return */ @JsonIgnore public String getFuncName() { return funcName; } /** * 设置点击页码调用的js函数名称,默认为page,在一页有多个分页对象时使用。 * @param funcName 默认为page */ public void setFuncName(String funcName) { this.funcName = funcName; } /** * 获取分页函数的附加参数* @return */ @JsonIgnore public String getFuncParam() { return funcParam; } /** * 设置分页函数的附加参数* @return */ public void setFuncParam(String funcParam) { this.funcParam = funcParam; } /** * 设置提示消息,显示在“共n条”之后* @param message */ public void setMessage(String message) { this.message = message; } /** * 分页是否有效* @return this.pageSize==-1 */ @JsonIgnore public boolean isDisabled() { return this.pageSize==-1; } /** * 是否进行总数统计* @return this.count==-1 */ @JsonIgnore public boolean isNotCount() { return this.count==-1; } /** * 获取Hibernate FirstResult */ public int getFirstResult(){ int firstResult = (getPageNo() - 1) * getPageSize(); if (firstResult >= getCount()) { firstResult = 0; } return firstResult; } /** * 获取Hibernate MaxResults */ public int getMaxResults(){ return getPageSize(); } }看完这个Page对象应该稍微有点感觉了吧,然后我在胡乱贴一些相关用到的工具类吧,工具类的话我只稍微提一下,具体大家可以弄到自己的代码上好好解读。
PropertiesLoader.java 用来获取resource文件夹下的常量配置文件
package com.store.base.secondmodel.base.util; import java.io.IOException; import java.io.InputStream; import java.util.NoSuchElementException; import java.util.Properties; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; /** * Properties文件载入工具类. 可载入多个properties文件, * 相同的属性在最后载入的文件中的值将会覆盖之前的值,但以System的Property优先. * @author yiyong_wu * */ public class PropertiesLoader { private static Logger logger = LoggerFactory.getLogger(PropertiesLoader.class); private static ResourceLoader resourceLoader = new DefaultResourceLoader(); private final Properties properties; public PropertiesLoader(String... resourcesPaths) { properties = loadProperties(resourcesPaths); } public Properties getProperties() { return properties; } /** * 取出Property,但以System的Property优先,取不到返回空字符串. */ private String getValue(String key) { String systemProperty = System.getProperty(key); if (systemProperty != null) { return systemProperty; } if (properties.containsKey(key)) { return properties.getProperty(key); } return ""; } /** * 取出String类型的Property,但以System的Property优先,如果都为Null则抛出异常. */ public String getProperty(String key) { String value = getValue(key); if (value == null) { throw new NoSuchElementException(); } return value; } /** * 取出String类型的Property,但以System的Property优先.如果都为Null则返回Default值. */ public String getProperty(String key, String defaultValue) { String value = getValue(key); return value != null ? value : defaultValue; } /** * 取出Integer类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常. */ public Integer getInteger(String key) { String value = getValue(key); if (value == null) { throw new NoSuchElementException(); } return Integer.valueOf(value); } /** * 取出Integer类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常*/ public Integer getInteger(String key, Integer defaultValue) { String value = getValue(key); return value != null ? Integer.valueOf(value) : defaultValue; } /** * 取出Double类型的Property,但以System的Property优先.如果都为Null或内容错误则抛出异常. */ public Double getDouble(String key) { String value = getValue(key); if (value == null) { throw new NoSuchElementException(); } return Double.valueOf(value); } /** * 取出Double类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容错误则抛出异常*/ public Double getDouble(String key, Integer defaultValue) { String value = getValue(key); return value != null ? Double.valueOf(value) : defaultValue.doubleValue(); } /** * 取出Boolean类型的Property,但以System的Property优先.如果都为Null抛出异常,如果内容不是true/false则返回false. */ public Boolean getBoolean(String key) { String value = getValue(key); if (value == null) { throw new NoSuchElementException(); } return Boolean.valueOf(value); } /** * 取出Boolean类型的Property,但以System的Property优先.如果都为Null则返回Default值,如果内容不为true/false则返回false. */ public Boolean getBoolean(String key, boolean defaultValue) { String value = getValue(key); return value != null ? Boolean.valueOf(value) : defaultValue; } /** * 载入多个文件, 文件路径使用Spring Resource格式. */ private Properties loadProperties(String... resourcesPaths) { Properties props = new Properties(); for (String location : resourcesPaths) { InputStream is = null; try { Resource resource = resourceLoader.getResource(location); is = resource.getInputStream(); props.load(is); } catch (IOException ex) { logger.error("Could not load properties from path:" + location , ex); } finally { IOUtils.closeQuietly(is); } } return props; } }Global.java 用来获取全局的一些常量,可以是从配置文件中读取的常量,也可以是定义成final static的常量,获取配置文件的话是调用上面那个类进行获取的。
package com.store.base.secondmodel.base; import java.io.File; import java.io.IOException; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.DefaultResourceLoader; import com.google.common.collect.Maps; import com.store.base.secondmodel.base.util.PropertiesLoader; import com.store.base.secondmodel.base.util.StringUtils; /** * 全局配置类* @author yiyong_wu * */ public class Global { private static final Logger logger = LoggerFactory.getLogger(Global.class); /** * 当前对象实例*/ private static Global global = new Global(); /** * 保存全局属性值*/ private static Map<String, String> map = Maps.newHashMap(); /** * 属性文件加载对象*/ private static PropertiesLoader loader = new PropertiesLoader("application.properties"); /** * 显示/隐藏public static final String SHOW = "1"; public static final String HIDE = "0"; /** * 是/否*/ public static final String YES = "1"; public static final String NO = "0"; /** * 状态上/下app专用*/ public static final String UPSHVELF = "1"; public static final String DOWNSHVELF = "2"; public static final String SEPARATOR = "/"; /** * 对/错*/ public static final String TRUE = "true"; public static final String FALSE = "false"; /** * 上传文件基础虚拟路径*/ public static final String USERFILES_BASE_URL = "/userfiles/"; /** * 针对富文本编辑器,结尾会产生的空div */ public static final String ENDS = "<p><br></p>"; /** * 默认空的私有构造函数*/ public Global() { //do nothing in this method,just empty } /** * 获取当前对象实例*/ public static Global getInstance() { return global; } /** * 获取配置*/ public static String getConfig(String key) { String value = map.get(key); if (value == null){ value = loader.getProperty(key); map.put(key, value != null ? value : StringUtils.EMPTY); } return value; } /** * 获取URL后缀*/ public static String getUrlSuffix() { return getConfig("urlSuffix"); } /** * 页面获取常量* @see ${fns:getConst('YES')} */ public static Object getConst(String field) { try { return Global.class.getField(field).get(null); } catch (Exception e) { logger.error("获取常量出错", e); } return null; } /** * 获取工程路径* @return */ public static String getProjectPath(){ // 如果配置了工程路径,则直接返回,否则自动获取。 String projectPath = Global.getConfig("projectPath"); if (StringUtils.isNotBlank(projectPath)){ return projectPath; } try { File file = new DefaultResourceLoader().getResource("").getFile(); if (file != null){ while(true){ File f = new File(file.getPath() + File.separator + "src" + File.separator + "main"); if (f == null || f.exists()){ break; } if (file.getParentFile() != null){ file = file.getParentFile(); }else{ break; } } projectPath = file.toString(); } } catch (IOException e) { logger.error("加载配置文件失败", e); } return projectPath; } }CookieUtil.java 从名称就知道是针对获取和存储cookie的一个工具类
package com.store.base.secondmodel.base.util; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Cookie工具类* @author yiyong_wu * */ public class CookieUtils { private static final Logger logger = LoggerFactory.getLogger(CookieUtils.class); /** * 私有构造函数*/ private CookieUtils() { } /** * 设置Cookie(生成时间为1年) * @param name 名称* @param value 值*/ public static void setCookie(HttpServletResponse response, String name, String value) { setCookie(response, name, value, 60*60*24*365); } /** * 设置Cookie * @param name 名称* @param value 值* @param maxAge 生存时间(单位秒) * @param uri 路径*/ public static void setCookie(HttpServletResponse response, String name, String value, String path) { setCookie(response, name, value, path, 60*60*24*365); } /** * 设置Cookie * @param name 名称* @param value 值* @param maxAge 生存时间(单位秒) * @param uri 路径*/ public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) { setCookie(response, name, value, "/", maxAge); } /** * 设置Cookie * @param name 名称* @param value 值* @param maxAge 生存时间(单位秒) * @param uri 路径*/ public static void setCookie(HttpServletResponse response, String name, String value, String path, int maxAge) { Cookie cookie = new Cookie(name, null); cookie.setPath(path); cookie.setMaxAge(maxAge); try { cookie.setValue(URLEncoder.encode(value, "utf-8")); } catch (UnsupportedEncodingException e) { logger.error("不支持的编码", e); } response.addCookie(cookie); } /** * 获得指定Cookie的值* @param name 名称* @return 值*/ public static String getCookie(HttpServletRequest request, String name) { return getCookie(request, null, name, false); } /** * 获得指定Cookie的值,并删除。 * @param name 名称* @return 值*/ public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name) { return getCookie(request, response, name, true); } /** * 获得指定Cookie的值* @param request 请求对象* @param response 响应对象* @param name 名字* @param isRemove 是否移除* @return 值*/ public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name, boolean isRemove) { String value = null; Cookie[] cookies = request.getCookies(); if(cookies == null) { return value; } for (Cookie cookie : cookies) { if (cookie.getName().equals(name)) { try { value = URLDecoder.decode(cookie.getValue(), "utf-8"); } catch (UnsupportedEncodingException e) { logger.error("不支持的编码", e); } if (isRemove) { cookie.setMaxAge(0); response.addCookie(cookie); } } } return value; } }SpringContextHolder.java 主要是用来在java代码中获取当前的ApplicationContext,需要在spring配置文件中配置这个bean并且懒加载设置成false;
package com.store.base.secondmodel.base.util; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.DisposableBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @Service @Lazy(false) public class SpringContextHolder implements ApplicationContextAware, DisposableBean { private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class); private static ApplicationContext applicationContext = null; /** * 取得存储在静态变量中的ApplicationContext. */ public static ApplicationContext getApplicationContext() { assertContextInjected(); return applicationContext; } /** * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { assertContextInjected(); return (T) applicationContext.getBean(name); } /** * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. */ public static <T> T getBean(Class<T> requiredType) { assertContextInjected(); return applicationContext.getBean(requiredType); } @Override public void destroy() throws Exception { SpringContextHolder.clearHolder(); } /** * 实现ApplicationContextAware接口, 注入Context到静态变量中. */ @Override public void setApplicationContext(ApplicationContext applicationContext) { logger.debug("注入ApplicationContext到SpringContextHolder:{}", applicationContext); SpringContextHolder.applicationContext = applicationContext; if (SpringContextHolder.applicationContext != null) { logger.info("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext); } } /** * 清除SpringContextHolder中的ApplicationContext为Null. */ public static void clearHolder() { if (logger.isDebugEnabled()){ logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext); } applicationContext = null; } /** * 检查ApplicationContext不为空. */ private static void assertContextInjected() { Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder."); } }StringUtils.java字符串相关的一个工具类
package com.store.base.secondmodel.base.util; import java.io.UnsupportedEncodingException; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringEscapeUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.servlet.LocaleResolver; import com.store.base.util.Encodes; /** * 字符串帮助类* @author yiyong_wu * */ public class StringUtils extends org.apache.commons.lang3.StringUtils { private static final char SEPARATOR = '_'; private static final String CHARSET_NAME = "UTF-8"; private static final Logger logger = LoggerFactory.getLogger(StringUtils.class); /** * 转换为字节数组* @param str * @return */ public static byte[] getBytes(String str){ if (str != null){ try { return str.getBytes(CHARSET_NAME); } catch (UnsupportedEncodingException e) { logger.error("", e); return new byte[0]; } }else{ return new byte[0]; } } /** * 转换为字节数组* @param str * @return */ public static String toString(byte[] bytes){ try { return new String(bytes, CHARSET_NAME); } catch (UnsupportedEncodingException e) { logger.error("", e); return EMPTY; } } /** * 是否包含字符串* @param str 验证字符串* @param strs 字符串组* @return 包含返回true */ public static boolean inString(String str, String... strs){ if (str != null){ for (String s : strs){ if (str.equals(trim(s))){ return true; } } } return false; } /** * 替换掉HTML标签方法*/ public static String replaceHtml(String html) { if (isBlank(html)){ return ""; } String regEx = "<.+?>"; Pattern p = Pattern.compile(regEx); Matcher m = p.matcher(html); return m.replaceAll(""); } /** * 替换为手机识别的HTML,去掉样式及属性,保留回车。 * @param html * @return */ public static String replaceMobileHtml(String html){ if (html == null){ return ""; } return html.replaceAll("<([az]+?)//s+?.*?>", "<$1>"); } /** * 替换为手机识别的HTML,去掉样式及属性,保留回车。 * @param txt * @return */ public static String toHtml(String txt){ if (txt == null){ return ""; } return replace(replace(Encodes.escapeHtml(txt), "/n", "<br/>"), "/t", " "); } /** * 缩略字符串(不区分中英文字符) * @param str 目标字符串* @param length 截取长度* @return */ public static String abbr(String str, int length) { if (str == null) { return ""; } try { StringBuilder sb = new StringBuilder(); int currentLength = 0; for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) { currentLength += String.valueOf(c).getBytes("GBK").length; if (currentLength <= length - 3) { sb.append(c); } else { sb.append("..."); break; } } return sb.toString(); } catch (UnsupportedEncodingException e) { logger.error("", e); } return ""; } /** * 转换为Double类型*/ public static Double toDouble(Object val){ if (val == null){ return 0D; } try { return Double.valueOf(trim(val.toString())); } catch (Exception e) { logger.error("", e); return 0D; } } /** * 转换为Float类型*/ public static Float toFloat(Object val){ return toDouble(val).floatValue(); } /** * 转换为Long类型*/ public static Long toLong(Object val){ return toDouble(val).longValue(); } /** * 转换为Integer类型*/ public static Integer toInteger(Object val){ return toLong(val).intValue(); } /** * 获得i18n字符串*/ public static String getMessage(String code, Object[] args) { LocaleResolver localLocaleResolver = SpringContextHolder.getBean(LocaleResolver.class); HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); Locale localLocale = localLocaleResolver.resolveLocale(request); return SpringContextHolder.getApplicationContext().getMessage(code, args, localLocale); } /** * 获得用户远程地址*/ public static String getRemoteAddr(HttpServletRequest request){ String remoteAddr = request.getHeader("X-Real-IP"); if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("X-Forwarded-For"); } if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("Proxy-Client-IP"); } if (isNotBlank(remoteAddr)) { remoteAddr = request.getHeader("WL-Proxy-Client-IP"); } return remoteAddr != null ? remoteAddr : request.getRemoteAddr(); } /** * 驼峰命名法工具* @return * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toCamelCase(String s) { String s1 =s; if (s1 == null) { return null; } s1 = s.toLowerCase(); StringBuilder sb = new StringBuilder(s1.length()); boolean upperCase = false; for (int i = 0; i < s1.length(); i++) { char c = s1.charAt(i); if (c == SEPARATOR) { upperCase = true; } else if (upperCase) { sb.append(Character.toUpperCase(c)); upperCase = false; } else { sb.append(c); } } return sb.toString(); } /** * 驼峰命名法工具* @return * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toCapitalizeCamelCase(String s) { String s1 = s; if (s1 == null) { return null; } s1 = toCamelCase(s1); return s1.substring(0, 1).toUpperCase() + s1.substring(1); } /** * 驼峰命名法工具* @return * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toUnderScoreCase(String s) { if (s == null) { return null; } StringBuilder sb = new StringBuilder(); boolean upperCase = false; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); boolean nextUpperCase = true; if (i < (s.length() - 1)) { nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); } if ((i > 0) && Character.isUpperCase(c)) { if (!upperCase || !nextUpperCase) { sb.append(SEPARATOR); } upperCase = true; } else { upperCase = false; } sb.append(Character.toLowerCase(c)); } return sb.toString(); } /** * 转换为JS获取对象值,生成三目运算返回结果* @param objectString 对象串* 例如:row.user.id * 返回:!row?'':!row.user?'':!row.user.id?'':row.user.id */ public static String jsGetVal(String objectString){ StringBuilder result = new StringBuilder(); StringBuilder val = new StringBuilder(); String[] vals = split(objectString, "."); for (int i=0; i<vals.length; i++){ val.append("." + vals[i]); result.append("!"+(val.substring(1))+"?'':"); } result.append(val.substring(1)); return result.toString(); } }有了上面这些基础的东西,只需要在写一个控制层接口,就可以看到每次返回一个page对象,然后里面封装好了查询对象的列表,并且是按分页得出列表。
package com.store.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import com.store.base.secondmodel.base.Page; import com.store.base.secondmodel.pratice.model.Product; import com.store.base.secondmodel.pratice.service.ProductService; /** *TODO *2016年10月11日*yiyong_wu */ @RestController @RequestMapping("/product") public class ProductController { @Autowired private ProductService productService; @ResponseBody @RequestMapping(value="/getPageProduct") public Page<Product> getPageProduct(HttpServletRequest request,HttpServletResponse response){ Page<Product> page = productService.findPage(new Page<Product>(request,response), new Product()); return page; } }最后在看一下页面怎么使用这个page对象,这样我们就完整地介绍了这个一个分页功能,代码很多,但很完整。
<%@ page contentType="text/html;charset=UTF-8"%> <%@ include file="/WEB-INF/views/include/taglib.jsp"%> <html> <head> <title></title> <meta name="decorator" content="default" /> function page(n, s) { if (n) $("#pageNo").val(n); if (s) $("#pageSize").val(s); $("#searchForm").attr("action", "${ctx}/app/bank/list"); $("#searchForm").submit(); return false; } </script> </head> <body> <form:form id="searchForm" modelAttribute="XXXX" action="${ctx}/XXX" method="post"> <input id="pageNo" name="pageNo" type="hidden" value="${page.pageNo}" /> <input id="pageSize" name="pageSize" type="hidden" value="${page.pageSize}" /> <ul> <li> <label>是否上架:</label> <form:select id="status" path="status"> <form:option value="" label=""/> <form:options items="${fns:getDictList('yes_no_app')}" itemLabel="label" itemValue="value" htmlEscape="false"/> </form:select> </li> <li><input id="btnSubmit" type="submit" value="查询"/> <li></li> </ul> </form:form> <sys:message content="${message}" /> <sys:message content="${message}" /> <table id="contentTable"> <thead> <tr> <th>XXXX</th> <th>XXXX</th> <th>XXXX</th> <th>XXXX</th> <th>XXXX</th> <th>XXXX</th> <th>XXXX</th> <th>XXXX</th> </tr> </thead> <tbody> <c:forEach items="${page.list}" var="XXXX"> <tr> <td>${XXXX.name}</td> <td><a href="${ctx}/app/bank/form?id=${XXXX.id}">${XXXX.}</a></td> <td>${XXXX.}</td> <td>${XXXX.}</td> <td>${XXXX.}</td> <td>${fns:getDictLabel(XXXX.isHot, 'yes_no_app', '无')}</td> <td>${XXXX.}</td> <td><c:if test="${XXXX.status==1 }">上架</c:if> <c:if test="${XXXX.status==2 }">下架</c:if> </td> </tr> </c:forEach> </tbody> </table> <div>${page} <li style="padding-top: 6px;padding-left: 12px;float: left;">共${page.count}条</li></div> </body> </html>到这里就基本上把整个分页功能描述得比较清楚了,希望可以帮助到你们快速解决分页这个问题,当然要在前端显示分页漂亮的话要针对li做一些css样式啥的,最后祝福你可以快速掌握这个分页功能!
以上所述是小编给大家介绍的Mybatis常用分页插件实现快速分页处理技巧,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!