Antes de compartir el código de ejecución para toda la página de consulta, comprenda primero el proceso de ejecución.
1. Generalmente, utiliza el interceptor de complemento MyBatis para interceptar antes de la ejecución de SQL, y agregue el límite XX a la declaración de consulta
2. Use un objeto de página para ejecutar todo el proceso de ejecución. Este objeto de página requiere escribir componentes de paginación front-end en Java.
3. Use un conjunto relativamente completo de entidad de tres capas, DAO y servicio para respaldar esta arquitectura de paginación
4. Algunas clases auxiliares utilizadas en esta página
Nota: Hay mucho contenido compartido. No enumeraré los frascos requeridos uno por uno. Cuando use esta función de paginación, solo busque cualquier paquete de jar por la noche. Use el paquete Maven para importar lo más posible porque Maven puede reducir los conflictos de versión y otras ventajas.
Solo puedo decir que puede usar esta función de paginación más fácil lo más rápido posible. Si no lo entiende, agrégeme a QQ y discúblalo juntos. ¡No lo juro! Además, el artículo puede ser relativamente grande, pero tomarse un tiempo, leerlo y practicarlo definitivamente ganará mucho.
Paso 1: Dado que el tema gira en torno a cómo paginar, comencemos con MyBatis. Primero, sacaremos dos archivos de configuración más importantes relacionados con MyBatis para una breve comprensión. Uno es mybatis-config.xml, y el otro es el archivo de configuración de mapper correspondiente a la entidad. Escribiré comentarios en el archivo de configuración, y todos lo entenderán de un vistazo.
mybatis-config.xml
<! Doctype Configuration public "-// mybatis.org//dtd config 3.0 // en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <necuteation> <!-Parámetros globales-> <settings> <!-Hacer el mapeador global Mapeper en cache. -> <setting name = "cacheenabled" value = "false"/> <!-Enable o desactive la carga perezosa a nivel mundial. Cuando se deshabilitan, todos los objetos asociados se cargan instantáneamente. -> <setting name = "LazyLoadingEnabled" value = "true"/> <!-Cuando está habilitado, un objeto con una propiedad de carga perezosa cargará completamente cualquier propiedad cuando se llame. De lo contrario, cada propiedad se cargará según sea necesario. -> <setting name = "agressiveLaLyLoading" value = "true"/> <!-si a permitir que un solo sql devuelva múltiples conjuntos de datos (dependiendo de la compatibilidad del controlador) predeterminado: true-> <setting name = "multipleReSultSetSenabled" valor = "verdadero"/> <!-alias para columnas para columnas se puede utilizar (dependiendo de la compatibilidad del controlador) predeterminado: verdadero-n. valor = "true"/> <!- Permitir JDBC para generar claves primarias. Se requiere soporte de manejo. Si se establece en verdadero, esta configuración forzará la clave primaria generada, algunas unidades son incompatibles pero aún se pueden ejecutar. predeterminado: falso-> <setting name = "useGeneratedKeys" value = "false"/> <!-Especifique cómo myBatis mapea automáticamente columnas de la tabla base de datos Ninguna: no obscena parcial: parte completa: all-> <setting name = "AutomapingBehavior" Value = "Parcial"/> <!-Este es el tipo de ejecución predeterminado (simple: simple: Simple; Reuse: el Ejecutor puede reutilizar los estados de estado preparado. declaraciones y actualizaciones de lotes)-> <setting name = "DefaultExeCutortype" value = "simple"/> <!-Convertir campos usando Camel Nomenclature. -> <setting name = "mapunderscoretocamelcase" value = "true"/> <!-configuración de la sesión del rango de caché local: habrá una declaración de intercambio de datos: el alcance de la declaración (esto no será compartir datos) Defalut: sesión-> <setting name = "localCacheCope" value = "session"/> <!-configuración pero el tipo JDBC está vacío, algunos discursos necesitan especificar el valor, value predeterminado, y no especificar el tipo, y no especificar el tipo de especificación, y no es el tipo de especificación, y no es el tipo, y no es el tipo, y no es el tipo de especificación, y no es el tipo de especificación, y no es el tipo de especificación de valor predeterminado, y existe el otro, y existe el otro, y existe el tipo, y no se especifica el valor predeterminado, y no es el tipo de especificación. Insertar un valor nulo-> <setting name = "jdbctypefornull" value = "null"/> <setting name = "logPrefix" value = "dao."/> </etneafings> <!-alias es el nombre de un tipo java más corto-> <pystupealias> <Pystingealias type = "com.store.base.model.storeuser" alias = "usuarios" usuarios " <typealias type = "com.store.base.secondmodel.pratice.model.product" alias = "producto"> </typealias> <typealias type = "com.store.base.secondmodel.base.page" alias = "página"> </pypealias> </ossias> <! Necesitamos implementar esta página Interceptor nosotros mismos -> <glugins> <plugin interceptor = "com.store.base.secondmodel.base.pageinterceptor.paginationinterceptor"/> </glugins> </figuration>
Un productMapper.xml se usa como objeto de prueba, y este archivo mapper simplemente configura una declaración de consulta que debe usarse.
<? xml versión = "1.0" encoding = "utf-8"?> <! Doctype mapper public "-// mybatis.org//dtd mapper 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 como productname, product_no como productno, precio como precio </sql> <select id = "findlist" resultType = "com.store.base.secondmodel.pratice.model.product"> Select <incluye refid = "basecolumns"/> de t_store_product </elect> </mapper>
Paso 2: A continuación, realizaremos un análisis en profundidad y aprendizaje para este interceptor de paginación, principalmente incluyendo las siguientes clases y sus interfaces correspondientes
(1) Clase básica del Interceptor Base Interceptor
(2) Pagination Interceptor La clase de complemento de paginación que queremos usar, heredar la clase básica anterior
(3) SQLHELPER se usa principalmente para ejecutar declaraciones de conteo por adelantado, y también para obtener toda la declaración de paginación completa.
(4) El dialecto, mySQLDALECT, se usa principalmente para si la base de datos admite las declaraciones de límite y luego encapsula las declaraciones de límite completos
Las siguientes son las pantallas compartidas de estas categorías
BaseInterceptor.java
paquete com.store.base.secondmodel.base.pageinterceptor; import java.io.serializable; import java.util.properties; importar org.apache.ibatis.logging.log; importar org.apache.ibatis.logging.logFactory; importar 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 Clase * @author yiyong_wu * */ public abstract class BaseInterceptor implementa Interceptor, serializable {private Static Final Long SerialVersionUid = 1L; Página de cadena final estática protegida = "Página"; Cadena final estática protegida delegado = "delegado"; Cadena final estática protegida mapped_statement = "MappedStatement"; log protegido log = logFactory.getLog (this.getClass ()); dialecto de dialecto protegido; / *** Convertir y verificar los parámetros* @param ParameterObject ParametREJECT PARAMETERObject* @param Page Pagination Object* @return Pagination Object* @throws nosuchfieldException Parameter no se puede encontrar*/ @SuppressWarnings ("no comprobado") Página estatica protegida <Object> ConvertParameter (parámetro de parámetro de parámetro, Page <Object> Page Page {Intente {Pruebe {Pruebe {Pruebe {Pruebe {Pruebe {Pruebe {Pruebe {Page {Pruebe {Pruebe {Pruebe {Page {Pruebe {Pruebe {Pruebe {Pruebe {Pruebe {Pruebe {Intente: {return (page <ject>) parametREAntSt; } else {return (page <pectus>) refless.getFieldValue (parametreObject, página); }} capt (excepción e) {return null; }} /*** Establecer propiedades, admitir clases de dialecto personalizados y cómo formular bases de datos* <code> dialectclass </code>, clases de dialecto personalizados. Esto se puede configurar sin configurar * <Ode> DBMS </odode> Tipo de base de datos, base de datos compatible con el complemento * <code> sqlpattern </code> ID de SQL que necesita ser interceptado * @param p propiedades */protegido inicio initente (propiedades P) {dialect = null; Cadena dbtype = global.getConfig ("jdbc.type"); if ("mysql" .equals (dbtype)) {dialect = new mySqldialect (); } if (dalect == NULL) {Throw New RuntimeException ("Error del dialecto myBatis"); } Dialecto = dialecto; }}PaginationInterceptor.java
paquete com.store.base.secondmodel.base.pageinterceptor; import java.util.properties; importar org.apache.ibatis.executor.executor; importar org.apache.ibatis.mapping.boundsql; importar org.apache.ibatis.mapping.MappedStatement; importar org.apache.ibatis.mapping.sqlSource; importar org.apache.ibatis.plugin.Intercepts; importar org.apache.ibatis.plugin.invocation; importar org.apache.ibatis.plugin; importar org.apache.ibatis.plugin.signature; importar org.apache.ibatis.REFLECTION.MetaObject; importar org.apache.ibatis.session.resulthandler; importar 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; /*** Complemento de paginación de la base de datos, solo intercepta las declaraciones de consulta. * @author yiyong_wu * */ @intercepts ({@signature (type = ejecutor.class, método = "query", args = {mappedStatement.class, object.class, rowBounds.class, resulthandler.class})}) clase pública Paginationinterceptor extiende Baseinterceptor {Private Static SerialversionUdveruid = 1l; @Override Public Object Intercept (Invocation Invocation) lanza lanzable {final MappedStatement MappedStatement = (MappedStatement) Invocat.getArgs () [0]; Parámetro de objeto = invocation.getArgs () [1]; BoundSQL BoundSQL = MappedStatement.getBoundSQL (parámetro); Objeto parametREAnt = boundSql.getParametRoCject (); // Obtenga la página del objeto de parámetro de paginación <S Object> Page = NULL; if (parametREAnt! = NULL) {PAGE = ConvertParameter (ParameterObject, Page); } // Si se establece el objeto Paging, la paginación se realiza si (Page! = NULL && Page.getPageSize ()! = -1) {if (StringUtils.isblank (BoundSql.getSql ())) {return null; } String Originalsql = BoundSql.getSql (). Trim (); // Obtenga el número total de registros Page.SetCount (sqlhelper.getCount (Originalsql, NULL, MappedStatement, ParameterObject, BoundSQL, log)); // Consulta de paginación Objetos localizados para modificar la base de datos y prestar atención a modificar las cadenas de implementación páginasql = sqlhelper.GeneralPagesql (OriginalsQl, página, dialecto); invocation.getArgs () [2] = new RowBounds (RowBounds.no_row_offset, RowBounds.No_Row_Limit); BoundSQL newboundSQL = new BoundSQL (MappedStatement.getConfiguration (), Pagesql, BoundSQL.GetParametermappings (), Boundsql.getParameterEntect ()); // Resuelve la falla del parámetro Pagination myBatis forach if if (refless.getFieldValue (BoundSQL, "Metaparameters")! = NULL) {MetaObject mo = (metaObject) reflexss.getFieldValue (BoundSQL, "Metaparameters"); Reflections.SetFieldValue (NewBoundSQL, "Metaparameters", Mo); } // Resuelve myBatis Pagination foreach Parameter Fails End MappedStatement Newms = CopyFromPedStatement (MappedStatement, new BoundSQLSQLSource (newboundsql)); invocation.getArgs () [0] = newms; } return invocation.proced (); } @Override Public Object Plugin (Object Target) {return Plugin.wrap (Target, este); } @Override public void setProperties (propiedades de propiedades) {super.initproperties (propiedades); } private MappedStatement CopyFromMappedStatement (MappedStatement MS, SQLSource NewsqlSource) {MappedStatement.Builder Builder = new MappedStatement.Builder (ms.getConfiguration (), ms.getid (), NewsqlSource, Ms.getSqlCommandTypee ()); 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 implementa SQLSource {BoundSQL BoundSql; public BoundSQLSQLSource (BoundSQL BoundSql) {this.BoundSql = BoundSql; } @Override public BoundSQL getBoundSql (Object ParameterObject) {return BoundSql; }}}Sqlhelper.java
paquete com.store.base.secondmodel.base.pageinterceptor; import java.sql.connection; import java.sql.preparedStatement; import java.sql.resultset; import java.sql.sqlexception; import java.util.list; import java.util.regex.matcher; import java.util.regex.pattern; importar org.apache.ibatis.executor.errorContext; importar org.apache.ibatis.executor.executorException; importar org.apache.ibatis.logging.log; importar org.apache.ibatis.mapping.boundsql; importar org.apache.ibatis.mapping.MappedStatement; importar org.apache.ibatis.mapping.parametermapping; importar org.apache.ibatis.mapping.parametermode; importar org.apache.ibatis.REFLECTION.MetaObject; importar org.apache.ibatis.reflection.property.propertyTokenizer; importar org.apache.ibatis.scripting.xmltags.forEachsqlnode; importar org.apache.ibatis.session.configuration; importar org.apache.ibatis.type.typeHandler; importar 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; Clase de herramienta de sql* /*** sql* @author yiyong_wu** /public Sql el objeto de la declaración. * @param mappedStatement mappedStatement * @param boundsql sql * @param parameteroBject parametREAntObject parametREAbject @throws java.sql.sqlexception Base de datos excepción */ @SuppressWarnings ("sin verificar") Public Static SetParameMeters (preparado Presps de ESTATIMENTO MAPPEPEDS MAPPEPEDTATEMENTES, BUNCHETSETSTATETSTATETSTATICS (BoundsTatement, BoundStatement. BoundSql, Object ParameterObject) lanza SQLException {ErrorContext.Instance (). Activity ("Establecer parámetros"). Object (mappedStatement.getParametermap (). getId ()); Lista <amametermapping> parametermappings = boundsql.getParametermappings (); if (parametermappings! = null) {configuración configuración = mappedStatement.getConfiguration (); TypeHandlerRegistry typeHandlerRegistry = Configuration.gettypeHandlerRegistry (); Metaobject metaObject = parametREAnt == null? NULL: Configuration.NewMetaObject (ParameterObject); for (int i = 0; i <parametermappings.size (); i ++) {parametermapping parametermapping = parametermappings.get (i); if (parametermapping.getMode ()! = parametermode.out) {valor de objeto; String Propertyname = parametermapping.getProperty (); PropertyTokenizer prop = New PropertyTokenizer (PropertyName); if (parametreObject == null) {value = null; } else if (typeHandlerRegistry.hastypeHandler (parametREAncject.getClass ())) {value = parametREAnt; } else if (boundsql.hasadditionalParameter (PropertyName)) {value = BoundSql.getAdDitionApParameter (PropertyName); } else if (PropertyName.StartSwith (foreachSqlnode.item_prefix) && BoundSql.hasadditionalParameter (prop.getName ())) {valor = boundsql.getAdDitionAlParameter (prop.getName ()); if (value! = null) {valor = configuration.newmetaObject (valor) .getValue (Propertyname.substring (prop.getName (). longitud ())); }} else {value = metaObject == null? nulo: metaobject.getValue (Propertyname); } @SupplesWarnings ("RawTypes") typeHandler typeHandler = parametermapping.gettypeHandler (); if (typeHandler == NULL) {Throw New ExecutorException ("No se encontró TypeHandler para el parámetro" + PropertyName + "de la declaración" + MappedStatement.getId ()); } typeHandler.setParameter (PS, i + 1, valor, parametermapping.getJdbctype ()); }}}}} / *** consulta registros totales* @param sql sql instrucción* @param conexión de la base de datos de conexión* @param mappedStatement asignado* @param parametREAntOntsql parámetro* @param boundsql boundsql* @return Total número de registros* @throws sqlexception sql error* / público static int getCount (string string final, final, conexión, conexión, finalización final. MappedStatement MappedStatement, parámetro de parámetro final, final BoundSQL Boundsql, log log) lanza SQLException {String dbName = global.getConfig ("jdbc.type"); String final CountSQL; if ("oracle" .equals (dbname)) {countSql = "Seleccione Count (1) de (" + SQL + ") tmp_count"; } else {CountSql = "Seleccionar recuento (1) desde (" + remover (sql) + ") tmp_count"; } Conexión conn = conexión; Preparado PS = NULL; ResultSet rs = null; Pruebe {if (log.isDebugeNabled ()) {log.debug ("Count sql:" + stringUtils.replaceEach (CountSql, new String [] {"/n", "/t"}, nueva cadena [] {"", ""}); } if (conn == null) {conn = mappedStatement.getConfiguration (). getenvironment (). getDataSource (). getConnection (); } ps = conn.preparestatement (countSql); BoundSQL CountBs = new BoundSQL (MappedStatement.getConfiguration (), CountSql, BoundSql.getParametermappings (), ParametRoCject); // Resuelve la falla del parámetro Pagination myBatis forach if if (refless.getFieldValue (BoundSQL, "Metaparameters")! = NULL) {MetaObject mo = (metaObject) reflexss.getFieldValue (BoundSQL, "Metaparameters"); Reflections.SetFieldValue (Countbs, "Metaparameters", Mo); } // Resuelve myBatis Pagination foreach Parameter Fails Fin Sqlhelper.SetParameters (PS, MappedStatement, CountS, ParametREAntObject); rs = ps.ExecuteQuery (); int count = 0; if (rs.next ()) {count = rs.getInt (1); } recuento de retorno; } finalmente {if (rs! = null) {rs.close (); } if (ps! = null) {ps.close (); } if (conn! = null) {conn.close (); }}} / *** Genere páginas específicas de acuerdo con el dialecto de la base de datos* @param sql sql en @param sql mapper* @param página de la página objeto* @param dialect dialect type* @return sql* / public static string generatepagesql (string sql, página <objeto> página dialect) {if ((dialect.supportsuppages (string sql, página <Object> Página, página de dialect) {if (((dialect. dialect.getLimitString (sql, page.getFirStresult (), page.getMaxResults ()); } else {return sql; }} /*** Eliminar la cláusula de selección de QlString. * @param hql * @return */ @supplesswarnings ("no usado") cadena estática privada eliminar (cadena qlString) {int beginpos = qlString.tolowerCase (). indexOf ("desde"); return QlString.Substring (beginpos); } /*** Eliminar la cláusula de orden de la Orden de HQL. *@param hql *@return */private static string removeRorders (String QlString) {Pattern P = Pattern.Compile ("Order // S *by [// w | // w | // s | // s] *", patrón.case_insensitive); Matcher m = p.matcher (QLString); StringBuffer sb = new StringBuffer (); while (m.find ()) {m.Appendreplontaltement (SB, ""); } m.appendtail (SB); return sb.ToString (); }}Interfaz dialect.java
paquete com.store.base.secondmodel.base.dialect; / *** Similar a Hibernate, pero solo la parte de la paginación se simplifica* @author yiyong_wu**/ public interface dialect {/ *** La base de datos en sí misma admite el método actual de consulta de la página para la consulta para la consulta* Si la base de datos no lo admite, la paginación de la base de datos no será la paginación** @Courn True: el método de consulta de la página actual*/ pública* / ** * Convertir SQL a Pagination SQL y llamar a Paging SQL por separado * * * @param SQL SQL Declaración * @param Número de compensación de inicio * @param Límite cuántos registros se muestran por página * @return sql para consulta de paginación */ public string getLimitString (string sql, int compensación, int límite); }Mysqldialect.java
paquete com.store.base.secondmodel.base.dialect; / ** * Implementación del dialecto mysql * @author yiyong_wu * */ public class mySqldialect implementa el dialecto {@Override public boolean SupportLimit () {return true; } @Override public String getLimitString (String sql, int offset, int límite) {return getLimitString (SQL, offset, integer.ToString (offset), integer.ToString (limit)); } /*** Convierta SQL en una declaración SQL paginada, proporcionando reemplazo de compensación y límite con el marcador de posición. * <pre> * Por ejemplo, mysql * dialect.getLiMitString ("Seleccionar * del usuario", 12, ": Offset", 0, ": Limit") devolverá * SELECT * DEL LIMITO DEL USUARIO: OFFSET,: LIMIT * </pre> * * @Param SQL Declaración real * @Param OffsetPlace -PAGATION PAGINACIÓN Inicio Registro de registro * @Param OffsetSetPhole Pagation Inicio Registro - Registro de registro Pagation - Registro de registro Pagation - Registro Pagin Posición de posicionador @return pagination sql que contiene marcadores de posición */ public string getLimitString (String sql, int offset, string offsetPeShuseHolder, string LimitplaceHolder) {StringBuilder StringBuilder = new StringBuilder (SQL); stringBuilder.append ("límite"); if (offset> 0) {StringBuilder.append (offsetPlaceHolder) .Append (","). Append (LimitplaceHolder); } else {StringBuilder.append (LimitplaceHolder); } return StringBuilder.ToString (); }}Casi aquí hemos compartido cómo implementar toda la página, pero tenemos tareas más importantes. Si queremos que todo se ejecute, debemos tener un trabajo básico que hacer. A continuación, analizamos todo el conjunto de objetos de página y la arquitectura de tres capas en la que se basa, y usamos el producto como entidad para el análisis. Después de hablar sobre una arquitectura completa de tres capas, las recompensas definitivamente estarán llenas. Hablemos de ello en el orden de entidad-> dao-> servicio a su vez.
Primero, debemos heredar dos clases de entidad abstractas, la centencia y la conciencia de datos para nuestras entidades.
BaseEntity.java principalmente coloca la variable de miembro de la página. Después de heredarlo, cada entidad puede tener esta variable miembro.
paquete com.store.base.secondmodel.base; import java.io.serializable; import java.util.map; import javax.xml.bind.annotation.xmltransient; importar org.apache.commons.lang3.stringutils; importar org.apache.commons.lang3.builder.reflectionToStringBuilder; import com.fasterxml.jackson.annotation.jsonignore; import com.google.common.collect.maps; import com.store.base.model.storeUser; / ** * La entidad de nivel superior * @author yiyong_wu * * @param <t> */ public abstract class BaseEntity <T> implementa serializable {private static final long serialversionUid = 1l; / ** * Eliminar la etiqueta (0: normal; 1: eliminar; 2: audit;) */ public static final String del_flag_normal = "0"; Cadena final estática pública del_flag_delete = "1"; Cadena final Public estática del_flag_audit = "2"; / *** Número de entidad (identificador único)*/ protegido ID de cadena; / *** Usuario actual*/ Protected StoreUser CurrentUser; / *** Objeto de paginación de entidad actual*/ página protegida <t> página; / ** * Custom SQL (identificador SQL, contenido sql) */ private map <string, string> sqlmap; Public baseEntity () {} public base basada (ID de cadena) {this (); this.id = id; } public String getId () {return id; } public void setid (ID de cadena) {this.id = id; } / *** Esto se llamará cuando se realice actualizaciones de inserción para shiro para obtener el usuario actual* @return* / @jsonignore @xmltransient public storeUser getCurrentUser () {if (currentUser == null) {// currentUser = userutils.getUser (); } return CurrentUser; } public void setCurrentUser (StoreUser CurrentUser) {this.currentUser = currentUser; } @Jsonignore @XmlTransient } página de retorno; } página pública <t> setPage (página <t> página) {this.page = page; página de regreso; } @Jsonignore @XmlTransient Map público <String, String> getSqlMap () {if (sqlmap == null) {sqlmap = maps.newhashmap (); } return sqlmap; } public void setsqlMap (map <string, string> sqlmap) {this.sqlmap = sqlmap; } / ** * Ejecutar el método antes de la inserción, subclase implementos * / public abstract void preinSert (); / ** * Ejecutar el método antes de la actualización, los implementos de subclase */ public abstract void preupdate (); /*** Si se trata de un nuevo registro (predeterminado: falso), llame a setisNewRecord () para establecer un nuevo registro y usar una ID personalizada. * Después de configurarlo en True, la instrucción Insertar se ve obligada a ejecutarse. La identificación no se generará automáticamente y debe pasar por manualmente. * @return */ public boolean getisnewrecord () {return stringUtils.isblank (getId ()); } / *** Objeto variable global* / @jsonignore public Global getGlobal () {return global.getInstance (); } / *** Obtener el nombre de la base de datos* / @jsonignore public String getDbName () {return global.getConfig ("jdbc.type"); } @Override public string toString () {return ReflectionToStringBuilder.ToString (this); }}DataSeTity.java, principalmente almacena y elimina el tiempo, crea usuarios, actualiza el usuario, el indicador de deleción lógica, etc.
paquete com.store.base.secondmodel.base; import java.util.date; importar org.hibernate.validator.constraints.length; import com.fasterxml.jackson.annotation.jsonformat; import com.fasterxml.jackson.annotation.jsonignore; import com.store.base.model.storeUser; / ** * Entidad de datos * @author yiyong_wu * * @param <t> */ public abstract Class DataSeTity <T> extiende BaseEntity <T> {Private estático final Long SerialVersionUid = 1L; Storeuser protegido Crearby; // Fecha protegida del creador creó; // Fecha de creación Protegida Storeuser UpdateBy; // Fecha de actualización de actualización actualizada; // String protegido de fecha actualizada delflag; // Eliminar etiqueta (0: normal; 1: eliminar; 2: audit) public dataEntity () {super (); this.delflag = del_flag_normal; } public DataSeTity (ID de cadena) {super (id); } / ** * Ejecutar el método antes de la inserción, debe llamar manualmente * / @Override public void preinSert () {// No hay restricción en la identificación a UUID, llame a setisNewRecord () para usar una identificación personalizada // usuario user = userutils.getUser (); // if (stringUtils.isnotblank (user.getID ())) {// this.updateby = user; // this.createBy = user; //} this.Updatedate = new Date (); this.createdate = this.updatedate; } / ** * Ejecutar el método antes de la actualización, debe llamar manualmente * / @Override public void preupdate () {// user user = userutil.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 (patrón = "yyyy-mm-dd hh: mm: ss") fecha pública getCreateDate () {return creatate; } public void setCreatedate (date creatateate) {this.createdate = creatateate; } // @Jsonignore Public StoreUser getUpdateBy () {return UpdateBy; } public void setupDateBy (StoreUser UpdateBy) {this.updateBy = updateBy; } @Jsonformat (patrón = "yyyy-mm-dd hh: mm: ss") pública fecha getUpdatedate () {return Updateateate; } public void setUpdatedate (fecha actualización) {this.Updatedate = updateateate; } @Jsonignore @Length (min = 1, max = 1) public String getDelflag () {return delflag; } public void setDelflag (string delflag) {this.delflag = delflag; }}Product.Java Categoría de productos
paquete com.store.base.secondmodel.pratice.model; import com.store.base.secondmodel.base.dataEntity; / ***Clase básica de productos*11 de octubre de 2016*yiyong_wu*/ Public Class Product extiende DataSentity <Product> {Private static final Long SerialVersionUid = 1l; Nombre de producto de cadena privada; precio flotante privado; Producto de cadena privada; public String getProductName () {return productName; } public void setProductName (string productName) {this.productName = productName; } public float getPrice () {precio de retorno; } public void setPrice (Price Float) {this.price = precio; } public String getProductno () {return productno; } public void setProductno (string productno) {this.productno = productno; }}¿Qué tal? ¿Ves una relación de herencia de entidad muy compleja? Pero, ¿qué hay? Cuanto más complejo sea, más completo será. A continuación, miraré la capa, las mismas tres capas, listas para ser bautizadas
Interfaz baseo.java reservada
paquete com.store.base.secondmodel.base; / ** * Interfaz DAO más alta * @author yiyong_wu * */ pública interfaz basada {} cruddao.java una capa de interfaz DAO para suma, eliminación, modificación y consulta [java] ver impresión de copia simple? Ver fragmentos de código en el código derivado de mi paquete de fragmentos de código com.store.base.secondmodel.base; import java.util.list; / ** * Defina la interfaz DAO para suma, eliminación, modificación y consulta * @author yiyong_wu * * @param <t> */ public interface cruddao <t> extiende a baseeao {/ ** * Obtenga una sola pieza de datos * @param id * @return */ public t get (string id); / ** * Obtenga una sola pieza de datos * @param entidad * @return */ public t get (t entidad); /*** Consulta la lista de datos. Si necesita paginación, configure el objeto de paginación, como: entity.setPage (nueva página <T> ()); * @param entidad * @return */ lista pública <t> findList (entidad t); / ** * Consulta Toda la lista de datos * @param entidad * @return */ lista pública <t> findallList (t entidad); /*** Consulta toda la lista de datos* @see Public List <T> FindallList (T Entity)* @return Public List <T> findallList (); *// ** * Insertar datos * @param entidad * @return */ public int Insert (t entidad); / ** * Actualizar datos * @param entidad * @return */ public int Update (t entidad); / ** * Eliminar datos (generalmente eliminación lógica, actualice el campo Del_Flag a 1) * @param id * @see public int delete (t entidad) * @return */ public int delete (ID de cadena); / ** * Eliminar datos (generalmente deleción lógica, actualice el campo Del_Flag a 1) * @param entidad * @return */ public int delete (entidad t); }Productdao.java mybatis La interfaz correspondiente mapeador también es una implementación DAO. Necesita personalizar la anotación @mybatisRepository
paquete 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 de octubre de 2016 *yiyong_wu */ @mybatisRepository interfaz pública ProductDao extiende Cruddao <Product> {}Anotación personalizada myBatisRepository.java está relacionada con la anotación personalizada. No explicaré demasiado aquí, hay mucha información en línea.
paquete com.store.base.secondmodel.base; import java.lang.annotation.documented; import java.lang.annotation.retention; import java.lang.annotation.target; import java.lang.annotation.retentionPolicy; import java.lang.annotation.ElementType; importar org.springframework.stereotype.component; /*** Identifique el DAO de MyBatis para facilitar el escaneo de {@link org.mybatis.spring.mapper.mapperscannerconfigurer}. * *Tenga en cuenta que desea configurar la configuración para escanear la clase anotada en el archivo de configuración de Spring * *<bean id = "mappersCannerConfigurer"> *<Property name = "sqlsessionFactoryBeanName" value = "sqlSessionFactory" /> *<name de propiedad = "BasePackage" value = "com.base.secondmodel" /> *<propiedad " /<propiedad" /<Propiedad " /<MOperation" name = "AnnotationClass" Value = "com.store.base.secondmodel.base.mybatisrePository"/> * </bean> * @author yiyong_wu * */@retention (retenciónPolicy.Runtime) @Target (elementType.type) @Documented Public @Coinface @interface @intery por defecto ""; } Nota: El archivo ProductMapper.xml que tiene una conexión sólida con Productdao.java es el archivo ProductMapper.xml. Puede ver que el espacio de nombres del archivo de configuración anterior apunta a la ruta a este DAO.
A continuación, ingresamos al análisis final del servicio, y también es una herencia de tres capas.
BaseService.java
paquete com.store.base.secondmodel.base; importar org.slf4j.logger; importar org.slf4j.loggerFactory; importar org.slf4j.loggerFactory; importar org.springframework.transaction.annotation.transactional; / ** * La clase de servicio principal de nivel superior * @author yiyong_wu * */ @transactional (readOnly = true) public abstract BaseService {// protegido logger = loggerFactory.getLogger (getClass ()); }Implementación de la interfaz comercial relacionada con Crudservice.Java
paquete com.store.base.secondmodel.base; import java.util.list; importar org.springframework.beans.factory.annotation.aUtowired; importar org.springframework.transaction.annotation.transactional; / ** * Agregar, eliminar, modificar y verificar la clase base de servicio * @author yiyong_wu * * @param <d> * @param <t> */ clase abstracta de la clase crudservice <d extiende cruddao <t>, t extiende la entrega de datos <T>> extiende el baseService {/ ** * objeto de la capa de persistencia */ @autowired D dao; / ** * Obtenga una sola pieza de datos * @param ID * @return */ public t get (ID de cadena) {return dao.get (id); } / ** * Obtenga una sola pieza de datos * @param entidad * @return * / public t get (t entidad) {return dao.get (entidad); } / ** * Datos de la lista de consultas * @param entidad * @return * / lista pública <t> findList (t entidad) {return dao.findList (entidad); } /** * 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; inicializar(); 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); } devolver ""; } /** * 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; /** * Global configuration class* @author yiyong_wu * */ public class Global { private static final Logger logger = LoggerFactory.getLogger(Global.class); /** * Current object instance*/ private static Global global = new Global(); /** * Save global attribute value*/ private static Map<String, String> map = Maps.newHashMap(); /** * Properties file loading object*/ private static PropertiesLoader loader = new PropertiesLoader("application.properties"); /** * Show/hide public static final String SHOW = "1"; public static final String HIDE = "0"; /** * Yes/No*/ public static final String YES = "1"; public static final String NO = "0"; /** * Status up/down app dedicated*/ public static final String UPSHVELF = "1"; public static final String DOWNSHVELF = "2"; public static final String SEPARATOR = "/"; /** * True/Wrong*/ public static final String TRUE = "true"; public static final String FALSE = "false"; /** * Basic virtual path of uploading file*/ public static final String USERFILES_BASE_URL = "/userfiles/"; /** * For rich text editors, empty divs will be generated at the end */ public static final String ENDS = "<p><br></p>"; /** * Default empty private constructor*/ public Global() { //do nothing in this method,just empty } /** * Get the current object instance*/ public static Global getInstance() { return global; } /** * Get the configuration*/ 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; } /** * Get URL suffix*/ public static String getUrlSuffix() { return getConfig("urlSuffix"); } /** * Page get constant* @see ${fns:getConst('YES')} */ public static Object getConst(String field) { try { return Global.class.getField(field).get(null); } catch (Exception e) { logger.error("Error getting constant", e); } return null; } /** * Get project path* @return */ public static String getProjectPath(){ // If the project path is configured, it will be returned directly, otherwise it will be automatically retrieved. 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("Loading configuration file failed", 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 tool class * @author yiyong_wu * */ public class CookieUtils { private static final Logger logger = LoggerFactory.getLogger(CookieUtils.class); /** * Private constructor */ private CookieUtils() { } /** * Set Cookie (generated time is 1 year) * @param name Name * @param value Value */ public static void setCookie(HttpServletResponse response, String name, String value) { setCookie(response, name, value, 60*60*24*365); } /** * Set Cookie * @param name Name * @param value Value * @param maxAge Survival time (units of seconds) * @param uri Path */ public static void setCookie(HttpServletResponse response, String name, String value, String path) { setCookie(response, name, value, path, 60*60*24*365); } /** * Set Cookie * @param name Name * @param value Value * @param maxAge Survival time (units of seconds) * @param uri path */ public static void setCookie(HttpServletResponse response, String name, String value, int maxAge) { setCookie(response, name, value, "/", maxAge); } /** * Set Cookie * @param name Name* @param value Value* @param maxAge Survival time (in seconds) * @param uri path */ 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("Unsupported encoding", e); } response.addCookie(cookie); } /** * Get the value of the specified cookie* @param name* @return value*/ public static String getCookie(HttpServletRequest request, String name) { return getCookie(request, null, name, false); } /** * Get the value of the specified cookie and delete it. * @param name name* @return value*/ public static String getCookie(HttpServletRequest request, HttpServletResponse response, String name) { return getCookie(request, response, name, true); } /** * Get the value of the specified cookie* @param request Request object* @param response Response object* @param name* @param isRemove Whether to remove* @return value*/ 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("UnsupportedEncoding", 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; /** * Get the ApplicationContext stored in a static variable. */ public static ApplicationContext getApplicationContext() { assertContextInjected(); return applicationContext; } /** * Get the bean from the static variable applicationContext and automatically transform it into the type of the assigned object. */ @SuppressWarnings("unchecked") public static <T> T getBean(String name) { assertContextInjected(); return (T) applicationContext.getBean(name); } /** * Get the bean from the static variable applicationContext and automatically transform it into the type of the assigned object. */ public static <T> T getBean(Class<T> requiredType) { assertContextInjected(); return applicationContext.getBean(requiredType); } @Override public void destroy() throws Exception { SpringContextHolder.clearHolder(); } /** * Implement the ApplicationContextAware interface and inject the Context into a static variable. */ @Override public void setApplicationContext(ApplicationContext applicationContext) { logger.debug("Inject ApplicationContext to SpringContextHolder:{}", applicationContext); SpringContextHolder.applicationContext = applicationContext; if (SpringContextHolder.applicationContext != null) { logger.info("The ApplicationContext in SpringContextHolder is overwritten, the original ApplicationContext is:" + SpringContextHolder.applicationContext); } } /** * Clear the ApplicationContext in SpringContextHolder to Null. */ public static void clearHolder() { if (logger.isDebugEnabled()){ logger.debug("Clear ApplicationContext in SpringContextHolder:" + applicationContext); } applicationContext = null; } /** * Check that the ApplicationContext is not empty. */ private static void assertContextInjected() { Validate.validState(applicationContext != null, "The applicaitonContext property is not injected, please define SpringContextHolder in applicationContext.xml."); }}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("..."); romper; }} return sb.ToString (); } catch (UnsupportedEncodingException e) { logger.error("", e); } devolver ""; } /** * 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 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(); } /** * 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(); 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常用分页插件实现快速分页处理技巧,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!