Sebelum berbagi kode eksekusi untuk seluruh halaman kueri, pahami proses eksekusi terlebih dahulu.
1. Secara umum, menggunakan mybatis plug-in interceptor untuk mencegat sebelum eksekusi SQL, dan menambahkan batas xx ke pernyataan kueri
2. Gunakan objek halaman untuk menjalankan seluruh proses eksekusi. Objek halaman ini membutuhkan komponen pagination front-end di Java.
3. Gunakan satu set entitas tiga lapis yang relatif lengkap, DAO, dan layanan untuk mendukung arsitektur pagination ini
4. Beberapa kelas tambahan yang digunakan di halaman ini
Catatan: Ada banyak konten yang dibagikan. Saya tidak akan mencantumkan stoples yang diperlukan satu per satu. Saat Anda menggunakan fungsi pagination ini, cari saja paket toples di malam hari. Gunakan paket Maven untuk mengimpor sebanyak mungkin karena Maven dapat mengurangi konflik versi dan keuntungan lainnya.
Saya hanya bisa mengatakan bahwa Anda dapat menggunakan fungsi paging yang lebih mudah ini secepat mungkin. Jika Anda tidak memahaminya, tambahkan saya ke QQ dan diskusikan bersama. Jangan bersumpah! Juga, artikel tersebut mungkin relatif besar, tetapi membutuhkan waktu, membacanya dan berlatih itu pasti akan mendapatkan banyak hal.
Langkah 1: Karena topik ini berkisar pada cara paginat, mari kita mulai dengan mybatis. Pertama, kami akan mengambil dua file konfigurasi yang lebih penting yang terkait dengan MyBatis untuk pemahaman singkat. Salah satunya adalah mybatis-config.xml, dan yang lainnya adalah file konfigurasi mapper yang sesuai dengan entitas. Saya akan menulis komentar pada file konfigurasi, dan semua orang akan memahaminya secara sekilas.
mybatis-config.xml
<! Doctype Configuration Public "-// mybatis.org//dtd config 3.0 // en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <Configuration> <!-Global Parameters-> <Pengaturan> <!-membuat global mapper atau global. -> <pengaturan name = "cacheenabled" value = "false"/> <!-mengaktifkan atau menonaktifkan malas memuat secara global. Saat dinonaktifkan, semua objek terkait dimuat secara instan. -> <pengaturan nama = "LazyLoadingEnabled" value = "true"/> <!-Saat diaktifkan, objek dengan properti pemuatan malas akan sepenuhnya memuat properti apa pun saat dipanggil. Jika tidak, setiap properti akan dimuat sesuai kebutuhan. -> <pengaturan nama = "agresivelazyloading" value = "true"/> <!-apakah akan mengizinkan satu SQL tunggal untuk mengembalikan beberapa dataset (tergantung pada kompatibilitas driver) default: true-> <pengaturan nama = "multipleresultSetsenabled" value = "true"/<!-apakah alias untuk kolom dapat digunakan (depending pada value "true" name = "usecolumnlabel" value = "true"/> <!- Izinkan JDBC untuk menghasilkan kunci primer. Dukungan drive diperlukan. Jika diatur ke True, pengaturan ini akan memaksa kunci primer yang dihasilkan, beberapa drive tidak kompatibel tetapi masih dapat dieksekusi. Default: false-> <pengaturan nama = "useGeneratedKeys" value = "false"/> <!-Tentukan bagaimana mybatis secara otomatis memetakan kolom tabel dasar data tidak ada: tidak mengaburkan parsial: bagian penuh: semua-> <pengaturan nama = "automapping baven" value = "parsial"/> <!-Ini adalah jenis eksekusi (Sederhana: Sederhana: Nilai = Partial "/> <! Ulangi pernyataan dan pembaruan batch)-> <pengaturan nama = "defaultExecutorType" value = "Simple"/> <!-Konversi bidang menggunakan nomenklatur unta. -> <pengaturan nama = "mapunderscoreTocamelcase" value = "true"/> <!-Mengatur sesi rentang cache lokal: akan ada pernyataan berbagi data: lingkup pernyataan (ini tidak akan menjadi data berbagi) defalut: sesi-> <pengaturan nama = tidak ada kebutuhan: value = "sesi"/> <!-pengaturan tetapi jenis jdbc, dan value no wears: value = "Sesi"/> <! Ketik saat memasukkan nilai null-> <pengaturan nama = "jdbctypefornull" value = "null"/> <pengaturan nama = "logprefix" value = "dao."/> </settings> <!-alias adalah nama tipe java yang lebih pendek-> <yypealisasi> <typealis type = "com.sore.base.base-baseasel" alias = "user"> </yypealias> <typealias type = "com.store.base.secondmodel.pratice.model.product" alias = "Produk"> </yypealis> <yypeali type = "com.store.base.secondmodel.base.page" page "page" page "page" page "page" page "page" <!-Konfigurasi plug-in, berikut adalah Page Interceptor yang dikonfigurasi untuk MyBatis, dan kami perlu mengimplementasikan halaman ini sendiri-> <lugin> <plugin interceptor = "com.store.base.secondmodel.base.pageinterceptor.paginationInterceptor"/</plugin> </configuration>
ProductMapper.xml digunakan sebagai objek uji, dan file mapper ini hanya mengonfigurasi pernyataan kueri yang perlu digunakan.
<? Xml Version = "1.0" encoding = "utf-8"?> <! Doctype mapper public "-// mybatis.org//dtd mapper 3.0 // en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> namespace = "com.store.base.secondmodel.pratice.dao.productdao"> <sql id = "basecolumns"> id, product_name sebagai productName, product_no sebagai productno, harga sebagai harga </sql> <pilih id = "findlist" resultType = "com.store.base.secondmodel.pratice.model.product"> pilih <include refid = "basecolumns"/> dari t_store_product </schect> </mapper>
Langkah 2: Selanjutnya, kami akan melakukan analisis dan pembelajaran mendalam untuk pencegat pagination ini, terutama termasuk kelas-kelas berikut dan antarmuka yang sesuai
(1) Kelas Dasar Interceptor Baseinterceptor
(2) PaginationInterceptor kelas plugin pagination yang ingin kami gunakan, mewarisi kelas dasar di atas
(3) Sqlhelper terutama digunakan untuk menjalankan pernyataan penghitungan sebelumnya, dan juga untuk mendapatkan seluruh pernyataan pagination lengkap.
(4) Dialek, mysqldialect, terutama digunakan untuk apakah database mendukung pernyataan batas, dan kemudian merangkum pernyataan batas lengkap
Berikut ini adalah tampilan berbagi dari kategori ini
Baseinterceptor.java
paket com.store.base.secondmodel.base.pageinterceptor; impor java.io.serializable; impor java.util.properties; impor org.apache.ibatis.logging.log; impor org.apache.ibatis.logging.logfactory; impor org.apache.ibatis.plugin.interceptor; impor com.store.base.secondmodel.base.global; impor com.store.base.secondmodel.base.page; impor com.store.base.secondmodel.base.dialect.dialect; impor com.store.base.secondmodel.base.dialect.mysqldialect; impor com.store.base.util.reflections; / ** * MyBatis Pagination Interceptor Base Class * @Author yiyong_wu * */ kelas abstrak publik Baseinterceptor mengimplementasikan interceptor, serializable {private static final long serialversionuid = 1L; halaman string final statis yang dilindungi = "halaman"; string final statis yang dilindungi delegasi = "delegasi"; string final statis yang dilindungi mapped_statement = "mappedstatement"; Log log yang dilindungi = logfactory.getLog (this.getClass ()); dialek dialek yang dilindungi; / *** Konversi dan periksa parameter* @param parameterobject ParameterObject ParameterObject* @param page pagination objek* @return pagination objek* @throws nosuchfieldException Parameter tidak dapat ditemukan*/ @suppresswarnings ("uncecked") PRYTATCE PAGE <Object> ConvertParameter ("tidak dicatat". {return (page <besop>) parameterObject; } else {return (page <papre>) reflections.getFieldValue (parameterObject, halaman); }} catch (Exception e) {return null; }} /*** Setel properti, mendukung kelas dialek khusus dan cara merumuskan database* <code> dialectclass </code>, kelas dialek khusus. Ini dapat dikonfigurasi tanpa mengkonfigurasi * <Ode> DBMS </ODE> Jenis database, database yang didukung oleh plug-in * <code> sqlpattern </code> ID SQL yang perlu dicegat * @param p properties */void void yang dilindungi (Properties P) {Dialect Dialect = NULL; String dBType = global.getConfig ("jdbc.type"); if ("mysql" .equals (dBType)) {dialect = new mysqldialect (); } if (dalect == null) {lempar runtimeException baru ("kesalahan dialek mybatis."); } Dialek = dialek; }}PaginationInterceptor.java
paket com.store.base.secondmodel.base.pageinterceptor; impor java.util.properties; impor org.apache.iatis.executor.executor; impor org.apache.ibatis.mapping.boundsql; impor org.apache.ibatis.mapping.mappedStatement; impor org.apache.ibatis.mapping.sqlsource; impor org.apache.ibatis.plugin.intercepts; impor org.apache.iatis.plugin.invocation; impor org.apache.iatis.plugin; impor org.apache.iatis.plugin.signature; impor org.apache.ibatis.reflection.metaObject; Impor org.apache.Ibatis.Session.ResulThandler; impor org.apache.ibatis.Session.rowbounds; impor com.store.base.secondmodel.base.page; impor com.store.base.secondmodel.base.util.stringutils; impor com.store.base.util.reflections; /*** Plugin Paging Database, hanya mencegat pernyataan kueri. * @Author yiyong_wu * */ @Intercepts ({@signature (type = executor.class, method = "query", args = {mappedstatement.class, objek.class, rowbounds.class, resulthandler.class})}) Public Class PaginationCeporscepor; @Override Public Object Intercept (Invocation Invocation) melempar Throwable {final MappedStatement MappedStatement = (MappedStatement) Invocation.getArgs () [0]; Parameter Objek = Invocation.getArgs () [1]; BoundSQL BoundSQL = MappedStatement.getBoundSQL (parameter); Objek parameterObject = boundsql.getParameterObject (); // Dapatkan halaman Objek Parameter Pagination <boject> halaman = null; if (parameterObject! = null) {page = convertParameter (parameterObject, halaman); } // Jika objek paging diatur, paging dilakukan jika (halaman! = Null && page.getPagesize ()! = -1) {if (stringutils.isBlank (boundsql.getSql ()))) {return null; } String originalsql = boundsql.getsql (). Trim (); // Dapatkan jumlah total catatan halaman.setCount (sqlhelper.getCount (Originalsql, null, mappedstatement, parameterObject, boundSQL, log)); // Pagination Query Objek Lokal untuk memodifikasi database dan memperhatikan untuk memodifikasi string implementasi PAGESQL = sqlhelper.generatePagesQL (Originalsql, halaman, dialek); Invocation.getArgs () [2] = RowBounds baru (rowbounds.no_row_offset, rowbounds.no_row_limit); BoundSQL newboundsql = boundSQL baru (mappedstatement.getConfiguration (), pagesql, boundsql.getParametermappings (), boundsql.getParameterObject ()); // Selesaikan pagination mybatis foreach parameter kegagalan mulai jika (reflections.getFieldValue (boundsql, "metaparameters")! = Null) {metaObject mo = (metaObject) reflections.getFieldValue (boundSQL, "metaparameters"); Reflections.SetFieldValue (NewboundSQL, "Metaparameters", MO); } // Selesaikan pagination mybatis foreach parameter kegagalan akhir pemetaan newMS = copyFrommappedStatement (mappedstatement, boundsqlsqlsource baru (newboundsql)); Invocation.getArgs () [0] = newms; } return Invocation.proed (); } @Override Plugin objek publik (target objek) {return plugin.wrap (target, ini); } @Override public void setProperties (Properties Properties) {super.InitProperties (properti); } private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) { MappedStatement.Builder builder = new MappedStatement.Builder( ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType()); 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 mengimplementasikan SQLSource {BoundSQL BoundSQL; Public BoundSQLSQLSource (BoundSQL BoundSQL) {this.boundsql = BoundSQL; } @Override Public BoundSQL GetBoundSQL (Object ParameterObject) {return BoundSQL; }}}Sqlhelper.java
paket com.store.base.secondmodel.base.pageinterceptor; impor java.sql.connection; impor java.sql.preparedstatement; impor java.sql.Resultset; impor java.sql.sqlexception; impor java.util.list; impor java.util.regex.matcher; impor java.util.regex.pattern; impor org.apache.ibatis.executor.errorcontext; impor org.apache.ibatis.executor.executorexception; impor org.apache.ibatis.logging.log; impor org.apache.ibatis.mapping.boundsql; impor org.apache.ibatis.mapping.mappedStatement; impor org.apache.ibatis.mapping.parametermapping; impor org.apache.ibatis.mapping.parametermode; impor org.apache.ibatis.reflection.metaObject; impor org.apache.ibatis.reflection.property.propertytokenizer; impor org.apache.ibatis.scripting.xmltags.foreachsqlnode; impor org.apache.ibatis.Session.configuration; impor org.apache.iathis.type.typehandler; Impor org.apache.ibatis.type.typehandlerregistry; impor com.store.base.secondmodel.base.global; impor com.store.base.secondmodel.base.page; impor com.store.base.secondmodel.base.dialect.dialect; impor com.store.base.secondmodel.base.util.stringutils; impor com.store.base.util.reflections; /*** SQL Tool Class* @author yiyong_wu** /kelas publik sqlhelper { /*** Konstruktor pribadi default* /private sqlhelper () {} /*** Tetapkan nilai sql parameter (?), Lihat org.apache.ibatis.executor.parameter.parameter. Objek pernyataan. * @param pemetaan pemetaan mappedstatement * @param boundsql sql * @param parameterobject parameterobject parameterobject @throws java.sql.sqlexception basis data pengecualian * @suppresswarnings ("tidak dicatat") public static setparameters (disiapkan ps, disiapkan ps, disiapkan ps, disiapkan ps, disiapkan ps, disiapkan ps, disiapkan ps, @suppresstatement (tidak dicetak " ParameterObject) melempar sqlexception {errorContext.Instance (). Activity ("Parameter Pengaturan"). Object (MappedStatement.GetParametermap (). getId ()); Daftar <Parametermapping> parameterMappings = BoundSQL.GetParametermappings (); if (parameterMappings! = null) {configuration configuration = mappedstatement.getConfiguration (); TypeHandlerRegistry typeHandlerRegistry = configuration.gettypehandlerregistry (); MetaObject metaObject = parameterObject == null? null: configuration.newmetaObject (parameterObject); untuk (int i = 0; i <parametermappings.size (); i ++) {parametermapping parametermapping = parametermappings.get (i); if (parametermapping.getMode ()! = parametermode.out) {nilai objek; String propertyname = parametermapping.getProperty (); PropertyTokenizer prop = PropertyTokenizer baru (PropertiDyName); if (parameterObject == null) {value = null; } lain jika (typeHandlerregistry.hastypehandler (parameterObject.getClass ())) {value = parameterObject; } lain if (boundsql.hasAdditionalparameter (propertiyname)) {value = boundsql.getAdditionalparameter (propertieName); } lain if (propertyname.startswith (foreachsqlnode.item_prefix) && boundsql.hasadditionalparameter (prop.getName ())) {value = boundsql.getAdditionalparameter (prop.getName ()); if (value! = null) {value = configuration.newMetaObject (value) .getValue (propertiyname.substring (prop.getName (). length ())); }} else {value = metaObject == null? null: metaObject.getValue (propertieName); } @SuppressWarnings ("RawTypes") typeHandler typeHandler = parametermapping.gettypehandler (); if (typeHandler == null) {throw new ExecutOrException ("Tidak ada typeHandler yang ditemukan untuk parameter" + propertiyname + "dari pernyataan" + mappedstatement.getId ()); } typeHandler.setParameter (ps, i + 1, value, parametermapping.getjdbctype ()); }}}} / *** Permintaan Total Catatan* @param SQL SQL Pernyataan* @param Koneksi Koneksi Basis Data* @param dipetakan mapped* @param parameterobject parameter* @param boundsql boundsql* @return jumlah catatan* @Throws SQLEXECECECTION SQL SQL ERRORT* / @RETURN STREAT PUBLIK PUBLIK* @Throws SQLEXECECECTION SQL ERRORT SQL ERROR ERRORED* @RETURN PUBLIK Public* MappedStatement, Final Object ParameterObject, Final BoundSQL BoundSQL, Log Log) Melempar SQLEXCEPTION {String dbName = Global.getConfig ("jdbc.type"); string terakhir Countsql; if ("oracle" .equals (dbName)) {countsql = "pilih count (1) dari (" + sql + ") tmp_count"; } else {countsql = "pilih count (1) dari (" + RemestORDERS (SQL) + ") tmp_count"; } Koneksi conn = koneksi; Disiapkan ps = null; Hasil rs = null; coba {if (log.isdebugeNabled ()) {log.debug ("hitung sql:" + stringutils.replaceeach (countsql, string baru [] {"/n", "/t"}, string baru [] {"", ""})); } if (conn == null) {conn = mappedstatement.getConfiguration (). getEnvironment (). getDataSource (). getConnection (); } ps = Conn.PrepareStatement (CountSQL); BoundSQL Countbs = BoundSQL baru (MappedStatement.GetConfiguration (), CountSQL, BoundSQL.GetParametermappings (), ParameterObject); // Selesaikan pagination mybatis foreach parameter kegagalan mulai jika (reflections.getFieldValue (boundsql, "metaparameters")! = Null) {metaObject mo = (metaObject) reflections.getFieldValue (boundSQL, "metaparameters"); Reflections.SetFieldValue (Countbs, "Metaparameters", MO); } // Selesaikan pagination mybatis foreach parameter kegagalan akhir sqlhelper.setParameters (ps, mappedstatement, countbs, parameterObject); rs = ps.executeQuery (); Int Count = 0; if (rs.next ()) {count = rs.getint (1); } jumlah pengembalian; } akhirnya {if (rs! = null) {rs.close (); } if (ps! = null) {ps.close (); } if (conn! = null) {conn.close (); } } } /** * Generate specific pages according to database dialect * @param sql Sql statement in @param sql Mapper* @param page paging object* @param dialect dialect type* @return paging SQL */ public static String generatePageSql(String sql, Page<Object> page, Dialect dialect) { if (dialect.supportsLimit()) { return dialect.getlimitString (sql, page.getFirStresult (), page.getmaxResults ()); } else {return sql; }} /*** Hapus Klausul Pilih QLString. * @param hql * @return */ @suppresswarnings ("tidak digunakan") string statis pribadi menghapus (string qlstring) {int beginpos = qlstring.tolowercase (). indexOf ("from"); return qlstring.substring (beginpos); } /*** Hapus Klausul Pesanan HQL. *@param hql *@return */string statis privat RemoveFor (string qlString) {pola p = Pattern.Compile ("order // s *oleh [// w | // w | // s | // s] *", pola.case_insensitive); Pencocokan m = p.matcher (qlstring); StringBuffer SB = StringBuffer baru (); while (m.find ()) {M.AppendReplacement (SB, ""); } M.Appendtail (SB); return sb.tostring (); }}Dialect.java antarmuka
paket com.store.base.secondmodel.base.dialect; / *** Mirip dengan Hibernate, tetapi hanya bagian paging yang disederhanakan* @Author yiyong_wu**/ dialek antarmuka publik {/ *** Apakah database itu sendiri mendukung metode kueri paging saat ini untuk pagar* jika database; Dukungan saat ini, page paging paging* paging* @return: dukungan saat ini, page paging paging* @RETRIT: DATABASE; DUKUNGAN KECEPATAN* / ** * Konversi SQL ke Pagination SQL dan Panggilan Paging SQL Secara terpisah * * @param SQL SQL Pernyataan * @param Offset Jumlah start * @param Batas berapa banyak catatan yang ditampilkan per halaman * @return sql untuk kueri pagination */ string publik getLimitstring (string sql, int offset, int limit); }Mysqldialect.java
paket com.store.base.secondmodel.base.dialect; / ** * Implementasi dialek MySQL * @author yiyong_wu * */ kelas publik MySqldialect mengimplementasikan dialek {@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 (limit)); } /*** Ubah SQL menjadi pernyataan SQL Paged, memberikan penggantian offset dan batas dengan placeholder. * <pr Pre> * Misalnya, mysql * dialect.getlimitString ("Select * From User", 12, ": Offset", 0, ": Limit") akan mengembalikan * Pilih * dari Batas Pengguna: Offset ,: Limit * </sumber Place -Nomor Place -Place -Place -Place -Nomor Place -Place. @Return Pagination SQL yang berisi placeholder */ Public String getLimitString (String SQL, int offset, String offsetplaceHolder, String LimitplaceHolder) {StringBuilder StringBuilder = New StringBuilder (SQL); StringBuilder.Append ("Limit"); if (offset> 0) {stringBuilder.append (offsetplaceHolder) .Append (","). append (limitplaceHolder); } else {StringBuilder.Append (LimitplaceHolder); } return stringBuilder.toString (); }}Hampir di sini kami telah berbagi cara mengimplementasikan seluruh halaman, tetapi kami memiliki tugas yang lebih penting. Jika kita ingin semuanya berjalan, kita harus memiliki pekerjaan dasar untuk dilakukan. Selanjutnya, kami menganalisis seluruh rangkaian objek halaman dan arsitektur tiga lapis yang didasarkan pada, dan menggunakan produk sebagai entitas untuk analisis. Setelah berbicara tentang arsitektur tiga lapis yang lengkap, imbalannya pasti akan penuh. Mari kita bicarakan dalam urutan entitas-> Dao-> pada gilirannya.
Pertama, kita harus mewarisi dua kelas entitas abstrak dasar dan data untuk entitas kita.
Baseentity.java terutama menempatkan variabel anggota halaman. Setelah mewarisi, setiap entitas dapat memiliki variabel anggota ini.
paket com.store.base.secondmodel.base; impor java.io.serializable; impor java.util.map; impor javax.xml.bind.annotation.xmltransient; impor org.apache.commons.lang3.stringutils; impor org.apache.commons.lang3.builder.reflectionToStringBuilder; impor com.fasterxml.jackson.annotation.jsonignore; impor com.google.common.collect.maps; impor com.store.base.model.storeuser; / ** * Entitas tingkat atas * @author yiyong_wu * * @param <t> */ Public Abstrak BaseEntity <T> Menerapkan serializable {private static final long serialVersionuid = 1L; / ** * hapus tag (0: normal; 1: hapus; 2: audit;) */ string final statis public del_flag_normal = "0"; string final statis public del_flag_delete = "1"; string final statis publik del_flag_audit = "2"; / *** Nomor entitas (pengidentifikasi unik)*/ ID string yang dilindungi; / *** Pengguna saat ini*/ StoreUser Currentuser yang Diprotes; / *** Objek Pagination Entitas Saat Ini*/ Halaman Dilindungi <T> Halaman; / ** * SQL Kustom (SQL Identifier, Konten SQL) */ 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; } / *** Ini akan dipanggil saat melakukan pembaruan. } return CurrentUser; } public void setCurrentUser (StoreUser CurrentUser) {this.currentUser = CurrentUser; } @Jsonignore @xmlTransient halaman publik <T> getPage () {if (page == null) {page = halaman baru <> (); } halaman kembali; } halaman publik <T> setPage (halaman <T> halaman) {this.page = halaman; halaman kembali; } @Jsonignore @xmltransient peta publik <string, string> getsqlmap () {if (sqlmap == null) {sqlmap = maps.newhashMap (); } return sqlmap; } public void setSqlMap (peta <string, string> sqlmap) {this.sqlmap = sqlmap; } / ** * Jalankan metode sebelum dimasukkan, implementasi subkelas * / public abstrak void preinsert (); / ** * Jalankan metode sebelum pembaruan, implementasi subkelas */ public abstrak void preupdate (); /*** Apakah itu catatan baru (default: false), hubungi setisNewRecord () untuk mengatur catatan baru, dan menggunakan ID khusus. * Setelah pengaturan ke True, pernyataan insert dipaksa untuk dieksekusi. ID tidak akan secara otomatis dihasilkan dan perlu diteruskan secara manual. * @return */ public boolean getisNewRecord () {return stringutils.isblank (getId ()); } / *** Objek Variabel Global* / @jsonignore Global Global GetGlobal () {return Global.getInstance (); } / *** Dapatkan nama basis data* / @jsonignore string publik getDbname () {return global.getConfig ("jdbc.type"); } @Override public string toString () {return reflectionToStringBuilder.toString (this); }}DataEntity.java, terutama menyimpan pembaruan dan menghapus waktu, membuat pengguna, memperbarui pengguna, bendera penghapusan logis, dll.
paket com.store.base.secondmodel.base; impor java.util.date; impor org.hibernate.validator.constraints.length; impor com.fasterxml.jackson.annotation.jsonformat; impor com.fasterxml.jackson.annotation.jsonignore; impor com.store.base.model.storeuser; / ** * Entitas data * @author yiyong_wu * * @param <t> */ DataEntity kelas abstrak publik <T> Memperluas BaseEntity <T> {private static final long serialVersionuid = 1L; StoreUser CreateBy yang dilindungi; // Tanggal Protected Creator dibuat; // Tanggal Pembuatan Pembaruan StoreUser Dilindungi; // pembaruan tanggal terlindungi diperbarui; // Tanggal yang Diperbarui String Delflag; // Hapus tag (0: normal; 1: hapus; 2: audit) dataEntity publik () {super (); this.delflag = del_flag_normal; } public DataEntity (string id) {super (id); } / ** * Jalankan metode sebelum dimasukkan, Anda perlu menelepon secara manual * / @Override public void preinsert () {// tidak ada batasan pada ID ke uuid, hubungi setisNewRecord () untuk menggunakan ID khusus // user user = userutils.getuser (); // if (stringutils.isnotblank (user.getid ())) {// this.updateBy = user; // this.createBy = user; //} this.updatedate = new date (); this.createdate = this.updatedate; } / ** * Jalankan metode sebelum diperbarui, Anda perlu menelepon secara manual * / @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 (pola = "yyyy-mm-dd hh: mm: ss") tanggal publik getCreateDate () {return createdate; } public void setCreateDate (tanggal dibuat) {this.createdate = createdate; } // @jsonignore Public Storeuser getUpdateBy () {return updateBy; } public void setupDateBy (StoreUser UpdateBy) {this.updateBy = updateBy; } @JsonFormat (pola = "yyyy-mm-dd hh: mm: ss") tanggal publik getUpdatedate () {return updateDate; } public void setupdatedate (tanggal diperbarui) {this.updatedate = updateDate; } @Jsonignore @length (min = 1, max = 1) public string getDelflag () {return delflag; } public void setDelflag (String delflag) {this.delflag = delflag; }}Product.java Kategori Produk
paket com.store.base.secondmodel.pratice.model; impor com.store.base.secondmodel.base.dataentity; / ***Produk Dasar -Dasar Kelas*11 Oktober 2016*yiyong_wu*/ Produk kelas publik memperluas DataEntity <product> {private static final long serialversionuid = 1l; Produk ProductName String Pribadi; harga pelampung pribadi; Produk string pribadi; Public String getProductName () {return productName; } public void setProductName (String ProductName) {this.productName = ProductName; } public float getPrice () {harga kembali; } public void setPrice (harga float) {this.price = harga; } public string getProductNo () {return productNo; } public void setProductNo (String ProductNo) {this.productno = ProductNo; }}Bagaimana dengan itu? Apakah Anda melihat hubungan warisan entitas yang sangat kompleks? Tapi apa yang ada? Semakin kompleks, semakin lengkapnya. Selanjutnya saya akan melihat lapisannya, tiga lapisan yang sama, siap dibaptis
BRODDENAO.JAVA INTERFACE Cadangan
paket com.store.base.secondmodel.base; / ** * Antarmuka DAO Teratas-Most * @author yiyong_wu * */ antarmuka publik berdasarkan {} cruddao.java Lapisan antarmuka DAO untuk penambahan, penghapusan, modifikasi dan kueri [java] Lihat cetak salin biasa? View Code Fragmen pada kode yang diturunkan ke paket fragmen kode saya com.store.base.secondmodel.base; impor java.util.list; / ** * Tentukan antarmuka DAO untuk penambahan, penghapusan, modifikasi, dan kueri * @author yiyong_wu * * @param <t> */ antarmuka publik cruddao <t> memperluas basis {/ ** * dapatkan satu bagian data * @param id * @return */ public t get (string id); / ** * Dapatkan sepotong data * @param entitas * @return */ public t get (t entitas); /*** Permintaan daftar data. Jika Anda memerlukan paging, silakan atur objek paging, seperti: Entity.setPage (halaman baru <T> ()); * @param entitas * @return */ daftar publik <t> findlist (t entitas); / ** * Permintaan semua daftar data * @param entitas * @return */ daftar publik <t> findAlllist (t entitas); /*** Permintaan semua DAFTAR DATA* @LENE PUBLIK PUBLIK <T> FindAllList (t entitas)* @return Daftar publik <T> findAllList (); *// ** * Sisipkan data * @param entitas * @return */ public int insert (t entitas); / ** * Perbarui data * @param entitas * @return */ pembaruan int publik (t entitas); / ** * Hapus data (biasanya penghapusan logis, perbarui bidang del_flag ke 1) * @param id * @see public int delete (t entitas) * @return */ public int delete (string id); / ** * Hapus data (biasanya penghapusan logis, perbarui bidang del_flag ke 1) * @param entitas * @return */ int hapus publik (t entitas); }Productdao.java Mybatis Antarmuka Mapper yang sesuai juga merupakan implementasi DAO. Anda perlu menyesuaikan anotasi @mybatisrepository
paket com.store.base.secondmodel.pratice.dao; impor com.store.base.secondmodel.base.cruddao; impor com.store.base.secondmodel.base.mybatisrepository; impor com.store.base.secondmodel.pratice.model.product; / ** *TODO *11 Oktober 2016 *yiyong_wu */ @mybatisrepository Public Interface Productdao memperluas cruddao <product> {}Anotasi khusus mybatisrepository.java terkait dengan anotasi khusus. Saya tidak akan menjelaskan terlalu banyak di sini, ada banyak informasi online.
paket com.store.base.secondmodel.base; impor java.lang.annotation.Documented; impor java.lang.annotation.Retention; impor java.lang.annotation.target; impor java.lang.annotation.RetentionPolicy; impor java.lang.annotation.elementType; impor org.springframework.stereotype.component; /*** Identifikasi dao mybatis untuk memfasilitasi pemindaian {@link org.mybatis.spring.mapper.mapperscannerConfigurer}. * *Harap dicatat bahwa Anda ingin mengonfigurasi konfigurasi untuk memindai kelas beranotasi dalam file konfigurasi pegas * *<bean id = "mapperscannerconfigurer"> *<name properti = "sqlSessionFactoryBeanName" value = "sqlSessionFactory" /> <property name = "Basepackage" value = "com." name = "annotationclass" value = "com.store.base.secondModel.base.mybatisrepository"/> * </tean> * @author yiyong_wu * */ @retention (retentionpolicy.runtime) @target (elementtype.type) @document @cument {@document {@document {elementypument) @cument @cument {elementyponicy (elementypument) bawaan ""; } Catatan: File ProductMapper.xml yang memiliki koneksi yang kuat dengan Productdao.java adalah file ProductMapper.xml. Anda dapat melihat bahwa namespace dari file konfigurasi di atas menunjuk ke jalur ke DAO ini.
Selanjutnya kita memasuki analisis layanan akhir, dan itu juga merupakan warisan tiga lapis.
Baseservice.java
paket com.store.base.secondmodel.base; impor org.slf4j.logger; impor org.slf4j.loggerFactory; impor org.slf4j.loggerFactory; impor org.springframework.transaction.annotation.transactional; / ** * Kelas layanan induk tingkat atas * @Author yiyong_wu * */ @transactional (readonly = true) kelas abstrak publik Baseservice {// Logger Logger = LoggerFactory.getLogger (getSclass ()); }CRUDSERVICE.JAVA Implementasi Antarmuka Bisnis Terkait
paket com.store.base.secondmodel.base; impor java.util.list; impor org.springframework.beans.factory.annotation.Autowired; impor org.springframework.transaction.annotation.transactional; / ** * Tambah, hapus, modifikasi, dan periksa kelas dasar layanan * @author yiyong_wu * * @param <d> * @param <t> */ kelas abstrak publik crudservice <d memperluas cruddao <t>, t memperluas data. / ** * Dapatkan sepotong data tunggal * @param ID * @return */ public t get (string id) {return dao.get (id); } / ** * Dapatkan sepotong data tunggal * @param entitas * @return * / public t get (t entitas) {return dao.get (entitas); } /** * 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; impor 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; initialize(); 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); } kembali ""; } /** * 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("..."); merusak; } } return sb.toString(); } catch (UnsupportedEncodingException e) { logger.error("", e); } kembali ""; } /** * 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 *October 11, 2016*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(); mengembalikan 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. Saya harap ini akan membantu semua orang. Jika Anda memiliki pertanyaan, silakan tinggalkan saya pesan dan editor akan membalas semua orang tepat waktu. Terima kasih banyak atas dukungan Anda ke situs web Wulin.com!