Avant de partager le code d'exécution pour toute la page de requête, comprenez d'abord le processus d'exécution.
1. Généralement, il utilise l'intercepteur du plug-in mybatis pour intercepter avant l'exécution de SQL et ajouter la limite xx à l'instruction de requête
2. Utilisez un objet de page pour exécuter l'ensemble du processus d'exécution. Cet objet de page nécessite d'écrire des composants de pagination frontale en Java.
3. Utilisez un ensemble relativement complet d'entités à trois couches, de DAO et de service pour prendre en charge cette architecture de pagination
4. Quelques classes auxiliaires utilisées dans cette page
Remarque: il y a beaucoup de contenu partagé. Je ne listerai pas les pots requis un par un. Lorsque vous utilisez cette fonction de pagination, recherchez simplement tous les paquets de bocal la nuit. Utilisez le package Maven pour importer autant que possible car Maven peut réduire les conflits de version et autres avantages.
Je peux seulement dire que vous pouvez utiliser cette fonction de pagination plus facile le plus rapidement possible. Si vous ne le comprenez pas, ajoutez-moi à QQ et discutez-en ensemble. Ne jurez pas! De plus, l'article peut être relativement important, mais prendre un certain temps, le lire et le pratiquer en gagnera certainement beaucoup.
Étape 1: Étant donné que le sujet tourne autour de la façon de paginer, commençons par mybatis. Tout d'abord, nous éliminerons deux fichiers de configuration plus importants liés à MyBatis pour une brève compréhension. L'un est MyBatis-Config.xml, et l'autre est le fichier de configuration du mappeur correspondant à l'entité. J'écrirai des commentaires sur le fichier de configuration et tout le monde le comprendra en un coup d'œil.
mybatis-config.xml
<! DocType Configuration publique "- // mybatis.org//dtd config 3.0 // en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <! - Global Paramètres -> <Imt settings> <! - Faire le maximum de maîtrise ou désactiver le cache. -> <setting name = "cacheenabled" value = "false" /> <! - Activer ou désactiver le chargement paresseux globalement. Lorsqu'ils sont désactivés, tous les objets associés sont chargés instantanément. -> <paramètre name = "LazyLoadingEnabled" value = "true" /> <! - Lorsque vous êtes activé, un objet avec une propriété de chargement paresseux chargera entièrement n'importe quelle propriété lorsqu'elle sera appelée. Sinon, chaque propriété sera chargée au besoin. -> <paramètre name = "AggressIveLyloading" value = "true" /> <! - que ce soit pour permettre à un seul SQL de renvoyer plusieurs ensembles de données (en fonction de la compatibilité du pilote) par défaut: true -> <paraming name = "MultipleResulTSetsEnty" Value = "true" /> <! - If alias for Columns peut être utilisé (en fonction de la compatibilité du pilote) par défaut) name = "usecolumnLabel" value = "true" /> <! - Autoriser JDBC à générer des clés primaires. La prise en charge du lecteur est requise. Si elle est définie sur true, ce paramètre forcera la clé primaire générée, certains disques sont incompatibles mais peuvent toujours être exécutés. Par défaut: false -> <setting name = "usegeneratedKeys" value = "false" /> <! - Spécifiez comment MyBatis mlase automatiquement les colonnes de la table de base de données non obscurcie partielle: partie complète: all -> <setting name = "AutomapingBehavior" vause = "partiel" /> <! - Il s'agit du type d'exécution par défaut (simple: Récevoir; Reuse: L'exécuteur peut réutiliser les étapes préparés; Instructions et mises à jour par lots) -> <paramètre name = "defaultExeCutOrType" value = "Simple" /> <! - Converti les champs à l'aide de Camel Nomenclature. -> <paramètre name = "MapundersCoretOcamelCase" value = "true" /> <! - Définition de la plage de cache locale Session: il y aura une instruction de partage de données: étendus de l'instruction (ce ne sera pas le partage de données) Defalute: Session -> <setting name = "localCachescope" value = "session" /> <! - Définition mais le type JDBC est vide, certains conducteurs doivent spécifier la valeur, par défaut: autrement, et il n'y a pas de spécification pour être vide pour être vide pour être vide pour Specif Insertion d'une valeur null -> <paramètre name = "jdbcTypeFornull" value = "null" /> <setting name = "logprefix" value = "dao." /> </ settings> <! - Alias est le nom d'un java type court -> <appenelias> <typeAlias type = "comi.store.base> <typealias type = "com.store.base.secondmodel.pratice.model.product" alias = "product"> </ typealias> <tycias type = "com.store.base.secondmodel.base.page" alias = "page"> </ / typealias> </pactalelias> <! Nous devons implémenter cette page Interceptor nous-mêmes -> <handins> <plugin interceptor = "com.store.base.secondmodel.base.pageInterceptor.paginationinterceptor" /> </glugins> </figionfing>
Un produitmapper.xml est utilisé comme objet de test, et ce fichier de mappeur configure simplement une instruction de requête qui doit être utilisée.
<? xml version = "1.0" Encoding = "UTF-8"?> <! Doctype Mappep Public "- // Mybatis.org//dtd Mappen 3.0 // en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace = "com.store.base.secondmodel.pratice.dao.productdao"> <sql id = "BaseColumns"> id, product_name as productName, product_no as productno resultType = "com.store.base.secondmodel.pratice.model.product"> select <inclure refid = "BaseColumns" /> from t_store_product </lect> </ mapper>
Étape 2: Ensuite, nous effectuerons une analyse et un apprentissage approfondis pour cet intercepteur de pagination, y compris principalement les classes suivantes et leurs interfaces correspondantes
(1) Classe de base de Base Interceptor Interceptor
(2) Pagination Interceptor La classe de plugin de pagination que nous voulons utiliser, hériter de la classe de base ci-dessus
(3) Sqlhelper est principalement utilisé pour exécuter les instructions de comptage à l'avance, et également pour obtenir l'intégralité de l'instruction de pagination complète.
(4) Le dialecte, MySQLDialect, est principalement utilisé pour savoir si la base de données prend en charge les instructions de limite, puis résumer les instructions de limite complète
Voici les affichages de partage de ces catégories
Base-interceptor.java
package com.store.base.secondmodel.base.pageInterceptor; import java.io.serializable; import java.util.properties; import org.apache.ibatis.logging.log; import org.apache.ibatis.logging.logfactory; import 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; / ** * MyBatis Pagination Interceptor Base Class * @author yiyong_wu * * / public abstrait class BaseInterceptor implémente interceptor, serializable {private static final long SerialVersionUID = 1l; Page de chaîne finale statique protégé = "page"; Protected static final String Delegate = "Delegate"; chaîne finale statique protégée mappéd_statement = "maptedstatement"; Log protégé Log = logfactory.getLog (this.getClass ()); dialecte dialecte protégé; /** * Convert and check parameters* @param parameterObject ParameterObject ParameterObject * @param page Pagination object* @return Pagination object* @throws NoSuchFieldException Parameter cannot be found*/ @SuppressWarnings("unchecked") protected static Page<Object> convertParameter(Object parameterObject, Page<Object> page) { try{ if (parameterObject instanceof Page) {return (page <Object>) ParameterObject; } else {return (page <Object>) Reflections.getFieldValue (ParameterObject, page); }} catch (exception e) {return null; }} / ** * Définir les propriétés, prendre en charge les classes de dialect personnalisées et comment formuler des bases de données * <code> dialectClass </code>, classes de dialect personnalisées. Cela peut être configuré sans configurer * <ODE> DBMS </ode> Type de base de données, base de données pris en charge par le plug-in * <code> sqlpattern </code> ID SQL qui doit être intercepté * @param p Properties * / Null protégée; String dbType = global.getConfig ("jdbc.type"); if ("mysql" .equals (dbType)) {dialect = new mysqldialect (); } if (dalect == null) {lancez new RuntimeException ("Mybatis dialect error."); } Dialect = dialect; }}Paginationinterceptor.java
package com.store.base.secondmodel.base.pageInterceptor; import java.util.properties; import org.apache.ibatis.executor.executor; import org.apache.ibatis.mapping.boundsql; import org.apache.ibatis.mapping.maptstatement; 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; import com.store.base.secondmodel.base.page; import com.store.base.secondmodel.base.util.stringutils; import com.store.base.util.reflections; / ** * Plugin de pagination de base de données, intercepte uniquement les instructions de requête. * @author yiyong_wu * * / @Intercepts ({@Signature (type = exécutor.class, méthode = "query", args = {mappedstatement.class, object.class, rowbounds.class, resulthandler.class})}) classe publique paginationid; @Override Public Object Intercept (Invocation Invocation) lève le throwable {final maptedstatement mapsstatement = (mappedstatement) invocation.getargs () [0]; Paramètre objet = invocation.getargs () [1]; BOUNDSQL BOURNSQL = MAPPEDSATAMENT.GETBOUNDSQL (Paramètre); Object ParameterObject = boundsql.getParameterObject (); // Obtenez la page d'objet du paramètre de pagination <objet> page = null; if (ParameterObject! = null) {page = convertParameter (ParameterObject, page); } // Si l'objet de pagination est défini, le paginage est effectué if (page! = Null && page.getPageSize ()! = -1) {if (stringUtils.isblank (boundsql.getsql ()))) {return null; } String OriginalSQL = BOUNDSQL.getsql (). TRIM (); // Obtenez le nombre total de enregistrements page.SetCount (sqlhelper.getCount (OriginalSQL, null, maptedstatement, ParameterObject, boundsql, log)); // Requête de pagination Objets localisés pour modifier la base de données et faire attention à la modification de la chaîne d'implémentation pagesql = sqlhelper.generatePagesql (OriginalSQL, page, dialect); invocation.getArgs () [2] = new RowBounds (rowbounds.no_row_offset, rowbounds.no_row_limit); BOUNDSQL NEWBOUNDSQL = NOUVEAU BOURNSQL (MAPPEDSATATION.GETCONFIGURATION (), PAGESQL, BOUNDSQL.GETPARAMETERMAPPing // Résoudre la pagination de MyBatis pour la défaillance des paramètres de paramètre IF (Reflections.getFieldValue (BOUNDSQL, "Metaparameters")! = NULL) {MetaObject Mo = (MetaObject) Reflections.getFieldValue (BoundsQL, "Metaparameters"); Reflections.setFieldValue (NewboundSQL, "Metaparameters", MO); } // Résoudre la pagination MyBatis ForEach FAILER DE PARAMETER FIN MAPPEDSATATION NEWMS = COPYFROMMAPTSATSATION (MAPPEDSATSATION, NOUVEAU BOURNSQLSQLLSOURCE (NewBoundSQL)); invocation.getArgs () [0] = newms; } return invocation.proceed (); } @Override Public Object Plugin (Object Target) {return plugin.wrap (Target, This); } @Override public void setProperties (Properties Properties) {super.initProperties (propriétés); } Private Maptedstatement CopyFrommAPPStAstation (MaptedStatement MS, SQLSource NewsQLSource) {mappedstatement.builder builder = new MaptedStatement.builder (Ms.GetSQLCom (), Ms.getid (); 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 ()); retour Builder.Build (); } Classe statique publique BoundSQLSQLSource implémente SQLSource {BOUNDSQL BOUNDSQL; public boundsqlSQLSource (boundsql boundsql) {this.boundsql = boundsql; } @Override public boundsql getBoundSQL (objet ParameterObject) {return boundsql; }}}Sqlhelper.java
package com.store.base.secondmodel.base.pageInterceptor; import java.sql.connection; Importer java.sql.PreparedStatement; import java.sql.resultSet; import java.sql.sqlexception; Importer java.util.list; import java.util.regex.matcher; import java.util.regex.pattern; 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.maptstatement; import org.apache.ibatis.mapping.ParameTermapping; 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.sse.Configuration; import org.apache.ibatis.type.typeHandler; import org.apache.ibatis.type.TypeHandlerRegistry; 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.util.stringutils; import com.store.base.util.reflections; / ** * SQL TOOL CLASS * @author yiyong_wu * * / public class sqlhelper {/ ** * Constructeur privé par défaut * / privé sqlhelper () {} / ** * Définissez la valeur pour les paramètres SQL (?), Reportez-vous à org.apache.ibatis.Executor.Parameter L'objet de la déclaration. * @Param MapPedStatement MapPedStatement * @param Boundsql SQL * @param ParameterObject ParameterObject ParameterObject @Throws Java.sql.Sqlexception Base de données Exception * / @Suppresswarning BoundsQL, Object ParameterObject) lève SQException {errorContext.instance (). Activity ("Setting Paramètres"). Object (mappedStatement.getParameTermap (). getID ()); List <paramètres de paramètres> Paramètres de paramètres = 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 <paramettermappings.size (); i ++) {paramètre paramètre paramètre = paramètres.get (i); if (ParameTerpapping.getMode ()! = ParameTermode.out) {Valeur d'objet; String PropertyName = ParameTermapping.getProperty (); PropertyTokenizer prop = new PropertyTokenizer (PropertyName); if (ParameterObject == null) {value = null; } else if (typeHandlerRegistry.hastypeHandler (ParameterObject.getClass ())) {value = ParameterObject; } else if (boundsql.hasadditionalParameter (propriétéName)) {value = boundsql.getAdditionalParameter (propriétéName); } else if (propriétéName.startswith (foreachsqlnode.item_prefix) && boundsql.hasadditionalParameter (prop.getName ())) {value = boundsql.getAdditionalPaMeter (prop.getName ()); if (value! = null) {value = configuration.newMetaObject (value) .getValue (propriétéName.SubString (prop.getName (). Length ())); }} else {value = metaObject == null? null: metaObject.getValue (PropertyName); } @SuppressWarnings ("RawTypes") TypeHandler TypeHandler = ParameTermapping.getTypeHandler (); if (typeHandler == NULL) {Throw New Executorexception ("Il n'y avait aucun type Handleur trouvé pour le paramètre" + propriétéName + "of Statement" + maptedStatement.getId ()); } typehandler.setParameter (ps, i + 1, valeur, paramètre.getjdbcType ()); }}}} / ** * Requête des enregistrements totaux * @Param SQL SQL Instruction * @Param Connection Database Connection * @Param MaptedStatement Mapted * @param ParameterObject Paramètre * @Param Boundsql Boundsql * @return Nombre total de disques * @throws SQLEXET CONNECTEMENT SQL CONNECNEMENT Finale * / Public Static Int GetCount (Final String Sql, Final Connection Error * / Public Static int GetCount MapPedStatement MapPedStatement, Final Object ParameterObject, Final BoundsQL BoundsQL, Log Log) lève Sqlexception {String dbname = global.getConfig ("JDBC.Type"); COUNTS FINAL COUNTSQL; if ("oracle" .equals (dbname)) {countSql = "select count (1) from (" + sql + ") tmp_count"; } else {countSql = "select count (1) FROM (" + removeOrders (sql) + ") tmp_count"; } Connexion conn = connection; PréparedStatement PS = null; ResultSet rs = null; try {if (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); BOUNDSQL COUNTBS = NOUVEAU BOURNSQL (MAPPEDSATATION.GETCONFIGURATION (), COUNTSQL, BOUNDSQL.GetParameTermAppings (), ParameterObject); // Résoudre la pagination de MyBatis pour la défaillance des paramètres de paramètre IF (Reflections.getFieldValue (BOUNDSQL, "Metaparameters")! = NULL) {MetaObject Mo = (MetaObject) Reflections.getFieldValue (BoundsQL, "Metaparameters"); Reflections.setFieldValue (Countbs, "Metaparameters", MO); } // Résoudre la pagination MyBatis pour la défaillance du paramètre End Sqlhelper.SetParameters (PS, MaptedStatement, CountBS, ParameterObject); rs = ps.ExecuteQuery (); int count = 0; if (Rs.Next ()) {count = Rs.GetInt (1); } Return Count; } enfin {if (rs! = null) {Rs.close (); } if (ps! = null) {ps.close (); } if (conn! = null) {conn.close (); }}} / ** * générer des pages spécifiques en fonction du dialect de la base de données * @param sql sql instruction in @param sql mapper * @param page objet de pagination * @param dialect dialect type * @return paging sql * / public static string static génératepagesql (String sql, page <object> page, dialect) {if (dialect.SUPPORT ()) dialect.getLimitstring (sql, page.getFirStResult (), page.getMaxResults ()); } else {return sql; }} / ** * Supprimez la clause SELECT de QlString. * @param hql * @return * / @SuppressWarnings ("inutilisé") String statique privée supprime (String qlString) {int débutpos = qlstring.tolowercase (). indexof ("from"); return qlString.substring (BeginPos); } / ** * Supprimez la clause OrderBy de HQL. * @param hql * @return * / private static string doupleDorders (String qlString) {Pattern p = motive.compile ("Order // S * by [// w | // w | // s | // s] *", pattern.case_insensitive); Matcher M = P.Matcher (QlString); StringBuffer sb = new StringBuffer (); while (m.find ()) {M.ApendReplacement (sb, ""); } M.ApendTail (SB); return sb.toString (); }}Interface dialect.java
package com.store.base.secondmodel.base.dialect; / ** * Similaire à Hibernate, mais seule la partie de pagination est simplifiée * @author yiyong_wu * * / Interface publique dialect {/ ** * La base de données elle-même prend en charge la méthode de requête de pagination actuelle pour la pagination * Si la base de données ne le prend pas en charge, la base de données de la base de données * / Public Boolan * * @return True: prend en charge la méthode de Query de quille actuelle * / ** * Convertir SQL en pagination SQL et pagination d'appels SQL séparément * * @param SQL SQL Instruction * @param Offset Number of Starts * @param limit combien de enregistrements sont affichés par page * @return SQL pour la pagination quey * / public String getLIMITSTRING (String SQL, int offSet, int limite); }Mysqldialect.java
package com.store.base.secondmodel.base.dialect; / ** * Implémentation du dialect mysql * @author yiyong_wu * * / public class MySQLDialect implémente le dialect {@Override public boolean supportLIMIT () {return true; } @Override public String getLIMITSTRING (String SQL, int offset, int limit) {return getLIMITSTRING (SQL, Offset, Integer.ToString (Offset), Integer.ToString (limite)); } / ** * Transformez SQL en une instruction SQL Paged, fournissant le remplacement du décalage et de la limite avec l'espace réservé. * <pre> * For example, mysql * dialect.getLimitString("select * from user", 12, ":offset",0,":limit") will return * select * from user limit :offset,:limit * </pre> * * @param sql Actual SQL statement * @param offsetPlaceholder Pagination start record number * @param offsetPlaceholder Pagination start record number - placeholder Pagination record number placeholder @return pagination sql contenant les espaces réservés * / public string getLIMITString (String sql, int offset, string offsetplaceholder, string limitplaceholder) {stringBuilder stringBuilder = new StringBuilder (sql); stringBuilder.append ("limite"); if (offset> 0) {StringBuilder.Apend (OffSetPlaceHolder) .Apnd (","). APPEND (LIMBLACKHOLDER); } else {StringBuilder.Apend (LIMBLACKHOLDER); } return StringBuilder.ToString (); }}Presque ici, nous avons partagé comment implémenter la page entière, mais nous avons des tâches plus importantes. Si nous voulons que le tout fonctionne, nous devons avoir un travail de base à faire. Ensuite, nous analysons l'ensemble des objets Page et l'architecture à trois couches sur lesquels il est basé et utilisons le produit comme entité pour l'analyse. Après avoir parlé d'une architecture complète à trois couches, les récompenses seront certainement pleines. Parlons-en dans l'ordre de l'entité-> dao-> Service à son tour.
Premièrement, nous devons hériter de deux classes abstraites de base de la base et de lantité données pour nos entités.
BaseEntity.java place principalement la variable du membre de la page. Après l'avoir hérité, chaque entité peut avoir cette variable de membre.
package com.store.base.secondmodel.base; import java.io.serializable; importation java.util.map; import javax.xml.bind.annotation.xmlTransient; 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; import com.store.base.model.storeuser; / ** * L'entité de niveau supérieur * @author yiyong_wu * * @param <T> * / public abstrait class BaseEntity <T> implémente serializable {private static final long SerialVersionUID = 1l; / ** * Supprimer la balise (0: normal; 1: delete; 2: Audit;) * / public static final string del_flag_normal = "0"; String final statique publique del_flag_delete = "1"; chaîne finale statique publique del_flag_audit = "2"; / ** * Numéro d'entité (identifiant unique) * / ID de chaîne protégé; / ** * Utilisateur actuel * / StoreUser protégé CurrentUser; / ** * Objet de pagination entité actuel * / page protégé <T> Page; / ** * Custom SQL (SQL Identifier, SQL Content) * / Private Map <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; } / ** * Ceci sera appelé lors de la réalisation de mises à jour d'insérer pour Shiro pour obtenir l'utilisateur actuel * @return * / @jsonignore @xmltransient public StoreUser getCurrentUser () {if (currentUser == null) {// currentUser = userUtils.getUser (); } return currentUser; } public void setCurrentUser (StoreUser CurrentUser) {this.currentUser = currentUser; } @Jsonignore @xmlTransient Public Page <T> getPage () {if (page == null) {page = new Page <> (); } page de retour; } page publique <T> setPage (page <T> page) {this.page = page; page de retour; } @Jsonignore @xmlTransient Public Map <String, String> GetSQlmap () {if (sqlmap == null) {sqlmap = maps.newhashmap (); } return sqlmap; } public void setsqlmap (map <string, string> sqlmap) {this.sqlmap = sqlmap; } / ** * Exécutez la méthode avant l'insertion, les outils de sous-classe * / public abstract void preInsert (); / ** * Exécutez la méthode avant la mise à jour, les outils de sous-classe * / public abstract void preupdate (); / ** * Qu'il s'agisse d'un nouvel enregistrement (par défaut: false), appelez setIsNewRecord () pour définir un nouvel enregistrement et utilisez un ID personnalisé. * Après avoir réglé sur true, l'instruction INSERT est forcée d'être exécutée. L'ID ne sera pas généré automatiquement et doit être transmis manuellement. * @return * / public boolean getisnewRecord () {return stringUtils.isblank (getID ()); } / ** * Objet variable global * / @jsonignore public global getGlobal () {return global.getInstance (); } / ** * Obtenez le nom de la base de données * / @jsonignore public String getDBName () {return global.getConfig ("jdbc.type"); } @Override public String toString () {return ReflectionToStringBuilder.ToString (this); }}Dataentity.java, stocke principalement la mise à jour et la suppression du temps, créez l'utilisateur, mettez à jour l'utilisateur, l'indicateur de suppression logique, etc.
package com.store.base.secondmodel.base; Importer java.util.date; import org.hibernate.validator.constraints.length; import com.fasterxml.jackson.annotation.jsonformat; import com.fasterxml.jackson.annotation.jsonignore; import com.store.base.model.storeuser; / ** * Entité de données * @author yiyong_wu * * @param <T> * / public abstract class dataentity <T> étend la base-importance <T> {private static final SerialVersionUID = 1l; StoreUser protégé CreateBy; // Date protégée du créateur CréationDate; // Création Date Protected StoreUser UpdateBy; // Date de mise à jour de mise à jour Updatedate; // Date mise à jour de la chaîne protégée delflag; // Delete Tag (0: Normal; 1: Delete; 2: Audit) public dataEntity () {super (); this.delflag = del_flag_normal; } public dataentity (String id) {super (id); } / ** * Exécutez la méthode avant l'insertion, vous devez appeler manuellement * / @Override public void preInsert () {// pas de restriction sur l'ID vers UUID, appelez setisnewRecord () pour utiliser un ID personnalisé // user user = userUtils.getUser (); // if (stringUtils.isnotblank (user.getId ())) {// this.updateby = user; // this.createby = utilisateur; //} this.updatedate = new Date (); this.Createdate = this.updatedate; } / ** * Exécutez la méthode avant la mise à jour, vous devez appeler manuellement * / @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") public date getCreatEdate () {return CreateDate; } public void setCreatEdate (date créée) {this.createdate = CreateDate; } // @jsonignore public StoreUser GetUpDateBy () {return updateBy; } public void setupDateBy (StoreUser UpdateBy) {this.updateby = updateBy; } @Jsonformat (pattern = "yyyy-mm-dd hh: mm: ss") public date getDatedate () {return updatedate; } public void setupDatedate (date updatedate) {this.updatedate = updatedate; } @Jsonignore @Length (min = 1, max = 1) public String getDelflag () {return delflag; } public void setDelflag (String delflag) {this.delflag = delflag; }}Catégorie de produit Product.Java
package com.store.base.secondmodel.pratice.model; import com.store.base.secondmodel.base.dataentity; / ** * Classe de bases du produit * 11 octobre 2016 * Yiyong_wu * / classe publique Le produit étend Dataentity <RODUCT> {privé statique final SerialVersionUID = 1l; String ProductName privé; prix flottant privé; Produit de chaîne privée; public String getProductName () {return productName; } public void setProductName (String productName) {this.productName = productName; } public float getPrice () {prix de retour; } public void setPrice (Float Price) {this.price = prix; } public String getProductNo () {return productNo; } public void setProductNo (String productNo) {this.productno = productNo; }}Et ça? Voyez-vous une relation de succession entité très complexe? Mais qu'est-ce qu'il y a? Plus il est complexe, plus il sera complet. Ensuite, je regarderai la couche, les mêmes trois couches, prête à être baptisée
Interface réservée réservée basée
package com.store.base.secondmodel.base; / ** * Interface DAO la plus la plus élevée * @author yiyong_wu * * / interface publique Basedao {} cruddao.java Une couche d'interface DAO pour l'addition, la suppression, la modification et la requête [Java] Affichage de la copie simple imprimer? Afficher les fragments de code sur le code dérivé de mon package de fragments de code com.store.base.secondmodel.base; Importer java.util.list; / ** * Définissez l'interface DAO pour l'addition, la suppression, la modification et la requête * @author yiyong_wu * * @param <T> * / Interface publique cruddao <T> étend Basedao {/ ** * Obtenez une seule pièce de données * @param id * @return * / public t Get (String id); / ** * Obtenez un seul élément de données * @param entité * @return * / public t get (t entité); / ** * Interrogez la liste des données. Si vous avez besoin de pagination, veuillez définir l'objet de pagination, tel que: entity.setPage (new Page <T> ()); * @param entité * @return * / public list <T> FindList (t entité); / ** * Recherchez toutes les données de données * @param entité * @return * / public list <T> findalllist (t entité); / ** * interroge toutes les listes de données * @see public list <T> findalllist (t entité) * @return public list <T> findallList (); * / / ** * INSERT DATA * @Param Entity * @return * / public int insert (t Entity); / ** * Mise à jour des données * @param entité * @return * / public int mette (t entité); / ** * Supprimer les données (généralement la suppression logique, mettez à jour le champ del_flag vers 1) * @param id * @see public int delete (t entité) * @return * / public int Delete (String id); / ** * Supprimer les données (généralement la suppression logique, mettez à jour le champ del_flag vers 1) * entité @param * @return * / public int Delete (t entité); }ProductDao.java MyBatis Correspondant Le mappeur est également une implémentation DAO. Vous devez personnaliser l'annotation @MyBatisRepository
package com.store.base.secondmodel.pratice.dao; import com.store.base.secondmodel.base.cruddao; import com.store.base.secondmodel.base.mybatisRepository; import com.store.base.secondmodel.pratice.model.product; / ** * TODO * 11 octobre 2016 * Yiyong_wu * / @MyBatiSrepository Interface publique ProductDao étend Cruddao <Rudding> {}Annotation personnalisée MyBatiSrepository.java est liée à l'annotation personnalisée. Je n'expliquerai pas trop ici, il y a beaucoup d'informations en ligne.
package com.store.base.secondmodel.base; import java.lang.annotation.documented; import java.lang.annotation.retention; import java.lang.annotation.target; Importer java.lang.annotation.retentionPolicy; import java.lang.annotation.elementType; import org.springframework.sterereotype.Component; / ** * Identifiez le DAO de Mybatis pour faciliter la numérisation de {@link org.mybatis.spring.mapper.mapperscannerconfigurer}. * * Veuillez noter que vous souhaitez configurer la configuration pour scanner la classe annotée dans le fichier de configuration de Spring * * <bean id = "MAPPERSCANNERCONFIGURER"> * <Property Name = "SqlSessionFactoryBeanName" Value = "SqlSessionFactory" /> * <propriété Name = "Basepackage" Value = "Comestore.Base.SecondModel" name = "annotationclass" value = "com.store.base.secondmodel.base.mybatisrepository" /> * </ bean> * @author yiyong_wu * * / @retention (retentionPolicy.runtime) @target (elementType.type) @Docuted @Pomponent public ""; } Remarque: Le fichier productMapper.xml qui a une connexion solide avec ProductDao.java est le fichier ProductMapper.xml. Vous pouvez voir que l'espace de noms du fichier de configuration ci-dessus pointe vers le chemin d'accès à ce DAO.
Ensuite, nous entrons dans l'analyse finale du service, et c'est également un héritage à trois couches.
BaseService.java
package com.store.base.secondmodel.base; import org.slf4j.logger; import org.slf4j.loggerfactory; import org.slf4j.loggerfactory; import org.springframework.transaction.annotation.transactional; / ** * La classe de service parent de niveau supérieur * @author yiyong_wu * * / @transactional (readonly = true) public abstrait class BaseService {// Protected Logger logger = loggerfactory.getLogger (getClass ()); }Implémentation d'interface commerciale liée à CrudService.Java
package com.store.base.secondmodel.base; Importer java.util.list; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.transactional; / ** * Ajouter, supprimer, modifier et vérifier la classe de base du service * @author yiyong_wu * * @param <d> * @param <T> * / public abstrait class CrudService <D étend cruddao <t>, t étend Dataentity <T>> étend le service de base de la persistance * / @Autowired Protection Dao Dao Protofred Dao Protofred DaO /** * Get a single piece of data* @param id * @return */ public T get(String id) { return dao.get(id); } /** * Get a single piece of data* @param entity * @return */ public T get(T entity) { return dao.get(entity); } /** * 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; /** * Pagination class* @author yiyong_wu * * @param <T> */ public class Page<T> implements Serializable{ private static final long serialVersionUID = 1L; private int pageNo = 1; // Current page number private int pageSize = Integer.parseInt(Global.getConfig("page.pageSize")); // Page size, set to "-1" means that no paging is performed (paging is invalid) private long count;// Total number of records, set to "-1" means that the total number is not queried private int first;// Home page index private int last;// Last page index private int prev;// Previous page index private int next;// Next page index private boolean firstPage;// Whether it is the first page private boolean lastPage;// Whether it is the last page private int length = 6;// Display page length private int slider = 1;// Display page length before and after private List<T> list = new ArrayList<>(); private String orderBy = ""; // Standard query is valid, example: updated desc, name asc private String funcName = "page"; // Set the name of the js function called by clicking on the page number. The default is page, and it is used when there are multiple paging objects on a page. private String funcParam = ""; // Additional parameter of the function, the third parameter value. private String message = ""; // Set the prompt message, displayed after "n total number of public Page() { this.pageSize = -1; } /** * Constructor method * @param request Pass the repage parameter to remember the page number * @param response is used to set cookies, remember the page number */ public Page(HttpServletRequest request, HttpServletResponse response){ this(request, response, -2); } /** * Constructor method * @param request Pass the repage parameter to remember the page number * @param response is used to set cookies, remember the page number * @param defaultPageSize The default paging size, if -1 is passed, it is not paged, and all data is returned */ public Page(HttpServletRequest request, HttpServletResponse response, int defaultPageSize){ // Set page number parameters (pass repage parameter to remember page number) 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)); } } // Set the page size parameter (pass the repage parameter to remember the page size) 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; } // Set the sorting parameters String orderBy = request.getParameter("orderBy"); if (StringUtils.isNotBlank(orderBy)){ this.setOrderBy(orderBy); } } /** * Constructor* @param pageNo Current page number* @param pageSize Pagination size*/ public Page(int pageNo, int pageSize) { this(pageNo, pageSize, 0); } /** * Constructor* @param pageNo Current page number* @param pageSize Pagination size* @param count Number of data strips*/ public Page(int pageNo, int pageSize, long count) { this(pageNo, pageSize, count, new ArrayList<T>()); } /** * Constructor* @param pageNo Current page number* @param pageSize Page size* @param count Number of data strips* @param list Data object list on this page*/ public Page(int pageNo, int pageSize, long count, List<T> list) { this.setCount(count); this.setPageNo(pageNo); this.pageSize = pageSize; this.list = list; } /** * Initialization parameter*/ 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) {// If the current page is smaller than the home page this.pageNo = this.first; } if (this.pageNo > this.last) {// If the current page is larger than the last page this.pageNo = this.last; } } /** * Default output current paging tag* <div>${page}</div> */ @Override public String toString() { StringBuilder sb = new StringBuilder(); if (pageNo == first) {// If it is the home page sb.append("<li class=/"disabled/"><a href=/"javascript:/">« Previous page</a></li>/n"); } else { sb.append("<li><a href=/"javascript:/" onclick=/""+funcName+"("+prev+","+pageSize+",'"+funcParam+"');/">« Previous page</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:/">Next page»</a></li>/n"); } else { sb.append("<li><a href=/"javascript:/" onclick=/""+funcName+"("+next+","+pageSize+",'"+funcParam+"');/">" + "next page»</a></li>/n"); } return sb.toString(); } /** * Get pagination HTML code* @return */ public String getHtml(){ return toString(); } /** * Get the total number of settings* @return */ public long getCount() { return count; } /** * Set the total number of data* @param count */ public void setCount(long count) { this.count = count; if (pageSize >= count){ pageNo = 1; } } /** * Get the current page number* @return */ public int getPageNo() { return pageNo; } /** * Set the current page number* @param pageNo */ public void setPageNo(int pageNo) { this.pageNo = pageNo; } /** * Get the page size* @return */ public int getPageSize() { return pageSize; } /** * Set page size (maximum 500) // > 500 ? 500 : pageSize; * @param pageSize */ public void setPageSize(int pageSize) { this.pageSize = pageSize <= 0 ? 10 : pageSize; } /** * Home page index* @return */ @JsonIgnore public int getFirst() { return first; } /** * Last page index* @return */ @JsonIgnore public int getLast() { return last; } /** * Get the total number of pages* @return getLast(); */ @JsonIgnore public int getTotalPage() { return getLast(); } /** * Is it the first page* @return */ @JsonIgnore public boolean isFirstPage() { return firstPage; } /** * Is it the last page* @return */ @JsonIgnore public boolean isLastPage() { return lastPage; } /** * Previous page index value* @return */ @JsonIgnore public int getPrev() { if (isFirstPage()) { return pageNo; } else { return pageNo - 1; } } /** * Next page index value* @return */ @JsonIgnore public int getNext() { if (isLastPage()) { return pageNo; } else { return pageNo + 1; } } /** * Get the data object list of this page* @return List<T> */ public List<T> getList() { return list; } /** * Set the data object list of this page* @param list */ public Page<T> setList(List<T> list) { this.list = list; initialiser(); return this; } /** * Get query sorting string* @return */ @JsonIgnore public String getOrderBy() { // SQL filtering to prevent injection of 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; } /** * Set query sorting, standard query is valid, Example: updated desc, name asc */ public void setOrderBy(String orderBy) { this.orderBy = orderBy; } /** * Get the name of the js function called by the click page number* function ${page.funcName}(pageNo){location="${ctx}/list-${category.id}${urlSuffix}?pageNo="+i;} * @return */ @JsonIgnore public String getFuncName() { return funcName; } /** * Set the name of the js function called by the click page number. The default is page, which is used when there are multiple paging objects on a page. * @param funcName Default is page */ public void setFuncName(String funcName) { this.funcName = funcName; } /** * Get additional parameters of the pagination function* @return */ @JsonIgnore public String getFuncParam() { return funcParam; } /** * Set additional parameters of the pagination function* @return */ public void setFuncParam(String funcParam) { this.funcParam = funcParam; } /** * Set the prompt message, displayed after "n total numbers"* @param message */ public void setMessage(String message) { this.message = message; } /** * Is the pagination valid* @return this.pageSize==-1 */ @JsonIgnore public boolean isDisabled() { return this.pageSize==-1; } /** * Whether to count the total number* @return this.count==-1 */ @JsonIgnore public boolean isNotCount() { return this.count==-1; } /** * Get Hibernate FirstResult */ public int getFirstResult() { int firstResult = (getPageNo() - 1) * getPageSize(); if (firstResult >= getCount()) { firstResult = 0; } return firstResult; } /** * Get 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 file loading tool class. Multiple properties files can be loaded, * The value of the same attribute in the last loaded file will overwrite the previous value, but System's Property takes precedence. * @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; } /** * Take out the Property, but System's Property takes priority, and the empty string cannot be returned. */ private String getValue(String key) { String systemProperty = System.getProperty(key); if (systemProperty != null) { return systemProperty; } if (properties.containsKey(key)) { return properties.getProperty(key); } retour ""; } /** * Take out the String property, but System's Property takes priority. If all are Null, an exception will be thrown. */ public String getProperty(String key) { String value = getValue(key); if (value == null) { throw new NoSuchElementException(); } return value; } /** * Take out the Property of type String, but the Property of the System is preferred. If it is Null, the Default value will be returned. */ public String getProperty(String key, String defaultValue) { String value = getValue(key); return value != null ? value : defaultValue; } /** * Take out the Property of type Integer, but the Property of the System is preferred. If it is Null or the content is wrong, an exception will be thrown. */ public Integer getInteger(String key) { String value = getValue(key); if (value == null) { throw new NoSuchElementException(); } return Integer.valueOf(value); } /** * Take out the Integer type Property, but the System's Property takes priority. If all are Null, the Default value will be returned, and an exception will be thrown if the content is wrong*/ public Integer getInteger(String key, Integer defaultValue) { String value = getValue(key); return value != null ? Integer.valueOf(value) : defaultValue; } /** * Take out the Double type Property, but the System's Property is preferred. If all are Null or the content is wrong, an exception will be thrown. */ public Double getDouble(String key) { String value = getValue(key); if (value == null) { throw new NoSuchElementException(); } return Double.valueOf(value); } /** * Take out the Double type Property, but the System's Property is preferred. If all are Null, a Default value will be returned. If all are Null, an exception will be thrown. */ public Double getDouble(String key, Integer defaultValue) { String value = getValue(key); return value != null ? Double.valueOf(value) : defaultValue.doubleValue(); } /** * Take out the Property of Boolean type, but the Property of the System is preferred. If all exceptions are thrown for Null, if the content is not true/false, it will return false. */ public Boolean getBoolean(String key) { String value = getValue(key); if (value == null) { throw new NoSuchElementException(); } return Boolean.valueOf(value); } /** * Take out the Boolean type Property, but System's Property takes priority. If all are Null, return the Default value, and if the content is not true/false, return false. */ public Boolean getBoolean(String key, boolean defaultValue) { String value = getValue(key); return value != null ? Boolean.valueOf(value) : defaultValue; } /** * Load multiple files, and the file path uses Spring Resource format. */ 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; /** * String help class* @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); /** * Convert to byte array* @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]; } } /** * Convert to byte array* @param str * @return */ public static String toString(byte[] bytes){ try { return new String(bytes, CHARSET_NAME); } catch (UnsupportedEncodingException e) { logger.error("", e); return EMPTY; } } /** * Does it contain strings* @param str Verification string* @param strs String group* @return contains 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; } /** * Replace HTML tag method*/ 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(""); } /** * Replace with HTML recognized by the phone, remove the style and attributes, and keep Enter. * @param html * @return */ public static String replaceMobileHtml(String html){ if (html == null){ return ""; } return html.replaceAll("<([az]+?)//s+?.*?>", "<$1>"); } /** * Replace with HTML recognized by the phone, remove the style and attributes, and keep Enter. * @param txt * @return */ public static String toHtml(String txt){ if (txt == null){ return ""; } return replace(replace(Encodes.escapeHtml(txt), "/n", "<br/>"), "/t", " "); } /** * Thumbnail string (not distinguishing between Chinese and English characters) * @param str Target string* @param length Intercept 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("..."); casser; } } return sb.toString(); } catch (UnsupportedEncodingException e) { logger.error("", e); } retour ""; } /** * Convert to Double type*/ 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; } } /** * Convert to Float type*/ public static Float toFloat(Object val){ return toDouble(val).floatValue(); } /** * Convert to Long type*/ public static Long toLong(Object val){ return toDouble(val).longValue(); } /** * Convert to Integer type*/ public static Integer toInteger(Object val){ return toLong(val).intValue(); } /** * Get i18n string*/ 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); } /** * Get the user remote address*/ 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(); } /** * Camel nomenclature tool* @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(); } /** * Camel nomenclature tool* @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); } /** * Camel Nomenclature Tool* @return * toCamelCase("hello_world") == "helloWorld" * toCapitalizeCamelCase("hello_world") == "HelloWorld" * toUnderScoreCase("helloWorld") = "hello_world" */ public static String toUnderScoreCase(String s) { if (s == null) { return nul; } 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(); } /** * Convert to JS to get the object value and generate the three-item operation to return the result* @param objectString object string* For example: row.user.id * Return: !row?'':!row.user?'':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(); retourne 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>Whether it is listed: </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="query"/> <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> <th>XXXX</th> <th>XXXX</th> <th>XXXX</th> <th>XXXX</th> </tr> </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', 'no')}</td> <td>${XXXX.}</td> <td><c:if test="${XXXX.status==1 }">On the shelves</c:if> <c:if test="${XXXX.status==2 }">Off</c:if> </td> </td> </tr> </c:forEach> </tbody> </table> <div>${page} <li style="padding-top: 6px;padding-left: 12px;float: left;">Total ${page.count} </li></div> </body> </html>到这里就基本上把整个分页功能描述得比较清楚了,希望可以帮助到你们快速解决分页这个问题,当然要在前端显示分页漂亮的话要针对li做一些css样式啥的,最后祝福你可以快速掌握这个分页功能!
The above is the skills of the commonly used paging plug-in for Mybatis to implement quick paging. J'espère que ce sera utile à tout le monde. Si vous avez des questions, veuillez me laisser un message et l'éditeur répondra à tout le monde à temps. Merci beaucoup pour votre soutien au site Web Wulin.com!