Written in front
Recently, I have learned Hibernate Struts, which is probably because I am dull, I always feel that things are not less (this is grateful to my predecessors), but the process is not too smooth. So I want to put some experience and questions here, one can ask you, and then provide a person who later learned. If you think that I have a problem, please be sure to make criticism and advice, I have criticized me to make progress, and I will advise me faster. I will start from the backend Hibernate before adding the part of the front end Struts. Since it is the relevant work content and doubt, it may look a little confusing, please bear. I hope that I have perseverance and perseverance to complete it ... In order to avoid infringing a headache such as our company's smart property, and the problem of business secrets, I decided not to use the system used by the company's online use (and its business logic has changed. It is a bit huge, and I don't know how to take it as a teaching document). It is called a comparison like a small toy grade as a sample program. The previous example will let it die with the wind ...
My reference data: 1. Hibernate Quick Start http://www.javaworld.com.tw/jute/post/view?bid=11&ID=3291&sty=1&tpg=1&age=-1 2. Introduction to Hibernate from theserverside http: / /www.theserverside.com/resources/articles/Hibernate/IntroductionToHibernate.pdf 3. Hibernate2 Reference Documentation http://www.hibernate.org/hib_docs/reference/pdf/hibernate_reference.pdf ========== ============================================================================================================================================================================================================= ==================== Feature requirements
We have to develop a (very Yangchun) photo management system, which is very simple. Based on: 1. Provide a new / modified / delete / query function to the photo. 2. In order to be more convenient to manage photos, we have to build a classification (which is the album), this classification is a class-like tree structure, that is, leaf node is an album, non-leaf node is an album. classification. (Classification must also have a new / modified / deleted / query function) 3. A plurality of photos can be included in one album, and a photo can also be classified in different albums at the same time.
Category design
Depending on the needs that have just been defined, two Domain Class can be set quickly, which is Photo and Album.
1. Photo: Record photo related information photo {id: long; single identification code filename: string; // Dynamic Title: string; // Photo Title Description: string; // Photo Description Albums: Set; // This photo belongs to the album} Thinking 1: ID of the data type with long instead of long, I saw the hibernate example is almost so useful. This is because long can have a null value, which is easy to determine that the object that has not been stored in the database in the database is very convenient. If you use long, 0 or -1, it may be easier to conflict with the real value. Also, why don't you use Integer? This, I don't know, probably the scope of Integer is not big enough. If you don't think about it, you are very troublesome when you are waiting until you go online ...
Thinking 2: Because repeated categories should not appear in Albums, use SET without other Collection to avoid accidents. In addition, Albums sorting, I want to use the classification ID as sorting basis.
2. Album: Record photo classification class architecture
Album {id: long; // The unique identification code used when // Persistent. Title: String; // Album Title Description: String; // Album Description Photos: set; // belonging to the following photo object Parent: Album; // Upper layer album classification Children: set; // belongs to this Classification Layer Photo Album Object}
Thinking 1: The same reason as Photo.albums, so use SET. This is a two-way Association, I can't think of a ternary, it said that if the two-way link is not good, it is changed to one-way. However, since Hibernate's example is written like this, then I will use this way, it should be no problem ...
Thinking 2: Because the entire album classification is a tree structure, it is necessary to have a Parent and Children to record architecture relationships between each other. Here is a problem, that is, whether the tree structure should have a common root? In other words, if I have three major categories [family], [student era], [other], should we build a common parent node for them? I personally compare the tendency to establish such (virtual) common parent nodes (taking "my album" well), when writing the program, can reduce the workload on many judgments.
My album | - family | | | - Dear wife adult | | | - Baby daughter | - Student era | | | University | | | - Institute | --other
============================================================================================================================================================================================================= =============================== Category
Because Album and Photo are Domain Objects, put it under Annhy.photo.domains. According to the previous category, we can easily put them out, but they currently have only Private Data Member and Getter / Setter Methods, which are unclosed Java Beans.
This is not enough, in order to make them better, we have to add something: a. Provide additional construction. In addition to the preset constructing, add the construction of a string parameter (filename). b. Oblocked toString (), equals (), havehcode (), etc. Object category. c. For the Comparable interface, as well as the Compareto (). d. Sets of reconstruction techniques for EncapSulate Collection (Package Cluster). (Note: P.208 in Refactoring Book has an encapsulate collection. In accordance with its statement, I should not provide getter / setter for the entire cluster (for example: photo.albums), and should be used The cluster add / remove element. So I add a corresponding function for these two Class, but I will not remove the original getter / setter to avoid hibernate.) E. Provide Finder Methods for searching Object. Because Finder Methods is higher than Hibernate, they extracted them out and moved to Albums.java with Photos.java. (Write later)
Photo.java:
Package annhy.photo.domains; import java.util. *; / ** * Used to represent the object of PHOTO data. * @Author Annhy * @version 1.0, 2003/10/01 * / public class photo imports comparable {// =========================================================================================================================================================================================================================== =============== public photo () {}
// For convenience, add a multi-build public photo (String filename) {this.filename = filename;
/ / ================ // == Data members // ========================== Private long id; private string filename Private string title; private set albums = new treset (); // has order, so use treset // ======================= ========= // == getter & setter methods / / =============================== = Public long getId () {return;} public void setid (long id) {this.id = id;}
Public string getFileName () {return filename;} public void setfilename (String filename) {this.filename = filename
Public string gettitle () {returnit;} public void settitle {this.title = title;}
Public string getdescription;} public void setdescription; {this.description = description;
Public set getalbums () {return albums;} public void setalbums (set albums) {this.albums = albums;
/ / ========================================================================================================================================================================== / ** * overwritten Object.toString () * @Return Debug String * / public string toString () {return "[photo": " filename "] ";} / ** * Object. Object.equals () * @Param Other wants to compare the other object * @return two objects Wait * / public boolean equals (object other) {if (● == this) {return true;} if (! {Return False;} Photo this = (photo)}
Return this.id.equals (this);}
/ ** * overwritten Object.hashcode () so that it can be used for Hash Code * / public int 6code () {returnid.id.hashcode ();}
/ ** * actual comparable.compareto () * @Param Other to compare another object * @return relatively small result * / public int compareto (Object Other) {Photo That = (photo)} @ .compareto (That.id);
/ / ============================================= // == Encapsulate Collection (package cluster) // ============================================= Public void addalbum (album album) {albums.add (album) ;
// Join the reverse link (To judge first !!) IF (! Album.getphotos (). Contains (this)) {album.addphoto (this);}} public void removealbum (album album) {albums.remove (album) );
// Remove the reverse link (to judge first !!) ife (album.getphotos (). Contains (this)) {album.removephoto (this);}}
Public void clearalbums () {// Record original snapshot album [] arrsnapshot = (album []) albums.toArray (new album [0]); for (int i = 0; i Album.java: Package annhy.photo.domains; Import java.util. *; / ** * The object used to represent a photo classification (album). * * @Author Annhy * @version 1.0, 2003/10/01 * / public class album imports comparable {// ======================================================================================================================================================================================= ============== Public album () {} // For convenience, add a construction-based public album (string title) {this.title = title; / / ==================== Data Members / / ======================================================================================================================================================================================================= Private string description; private set photos = new treset (); // there is order, so use treett private album parent; private set children = new treset (); // has order, so use Treeset / / ====================================================================================================================================================================================================================== ===========================} public void setId (long id) {this.id = ID; PUBLIC STRING GETTITLE () {Return Title;} public void settitle {this.title = title;} Public string getdescription;} public void setdescription; {this.description = description; Public set getphotos} public void setphotos {this.photos = Photos; Public album getparent () {return parent;} public void setparent (album parent) {this.parent = parent;} Public set getchildren () {return children;} public void setchildren (set children) {this.Children = children / / ========================================================================================================================================================================== / ** * overwritten Object.toString () * @Return Debug String * / public string toString () {return "[Album (" ID "):" Title "]"; / ** * overwritten Object.equals () * @Param Other to compare another object * @return two objects Wait * / public boolean equals (object other) {if (● == this) {Return True;} IF (! (@ · @StanceOf Album) {Return False;} Album That = (album) Other; return this.Id.equals (That.id);} / ** * overwritten Object.hashcode () so that it can be used for Hash Code * / public int 6code () {returnid.id.hashcode ();} / ** * Realt Comparable.Compareto () * @Param Other wants to compare another object * @return relatively small result * / public int compareto (Object Other) {album there = (album)} @ a .compareto (That.id); / / ============================================= // == Encapsulate Collection (package cluster) // ============================================= Public vid addphoto (photo photo) {Photos.Add (Photo) ; // Add a reverse link (must first judge !!) ife (! Photo.Getalbums (). Contains (this)) {photo.addalbum (this);}} Public void removephoto (photo photo) {photos.remove (photo); // Remove the reverse link (to judge first !!) IF (photo.getalbums (). Contains (this) {photo.removealbum (this);}} Public void clearphotos () {// Record original snapshot photo [] arrsnapshot = (photo []) photos.toArray (new photo [0]); for (int i = 0; i // Add a reverse link (to be judged first !!) if (! This.equals ())) {child.setparent (this);}} Public Void Removechild (Album Child) {Children.Remove (Child); // Remove the reverse link (to judge first !!) IF (this.equals ())) {child.setparent (null);}} Public void clearchildren () {// Record the original snapshot album [] arrsnapshot = (album []) Children.toArray (new album [0]); for (int i = 0; i Current file list: / Nannhy/photo/domains/photo.java /annhy/photo/domains/album.java ============================================================================================================================================================================================================= =============================== Set Hibernate related files After the Class is initially made, you can set the Hibernate-related files. Here are three files to do: hibernate.cfg.xml, photo.hbm.xml, album.hbm.xml (originally using hibernate.properties, you can have additional features, thank Browser guidance) Hibernate.cfg.xml: XML Version = "1.0" encoding = "big5"?> It should be noted here that this special string:? Useunicode = true & characterencoding = big5, I heard that this is because MySQL does not support Unicode, if not these, there is a problem with Chinese data. Also, because this is the file of XML format, so & AMP is replaced with & amp; (please change it yourself into a half! For this question, waste me for a few hours ...) Photo.hbm.xml: XML Version = "1.0" Encoding = "BIG5"?> XML Version = "1.0" Encoding = "BIG5"?> class> hibernate-maping> It is to be noted here: 1. When a two-way link is used, one of the CLASs must set inverse = "true". As for the Class of which is set, it doesn't seem to affect. 2. Because the Java.lang.String preset in MySQL corresponds to VARCHAR (255), this size is usually not enough, so for the following way, forced it to TEXT. (Thanks to Chrischang's Guidance This album.hbm.xml shows the relationship between MANY-TO-MANY, as well as the tree class architecture. These two special usage, I couldn't find examples before, I had to try. This is the result of my try, it is not bad, it is intuitive. Thinking 1: In the place where the correspondence is set, I have set lazy = "false" (not using Lazy Initialization), and cannot set the Class's Proxy property. This is because when I set these two options before I was closed after closing the session, I would read the photo.albums or albums.children these Collection generated Error. I know that hibernate is designed, but I don't understand, can the session do not close? (The manual is described above Session: a single-threaded, short-lived object ....) If it is a web ap, each http request is an independent action, this is not a problem? Before I don't understand, I still don't use it. Under the case of not much data volume, the top more is more efficient than the time ... Do you have a good heart to point me ... Current file list: / Nannhy/photo/Domains/photo.java /annhy/photo/domains/album.java /Hibernate.cfg.xml / Nannhy/photo/Domains/photo.hbm.xml / annhy / photo / domains / album .hbm.xml ============================================================================================================================================================================================================= =============================== Threadlocalsion.java, Photos.java, Albums.java Here, you have written Domain Class and Hibernate related files, we have enough things to generate test databases. I have to provide a public category used to get the session because I use the web program, so this public category must be Thread-Safe, so I refer to http://hibernate.bluemars.net/42.html http : //hibernate.bluemars.net/114.html, use the ThreadLocal variable to solve. Threadlocalsion.java: Package annhy.photo.hibernate; Import net.sf.hibernate. *; import net.sf.hibernate.cfg. *; public class ThreadLocalSession {// set Hibernate environment object is generated by the private static Configuration config xml mapping file; // SessionFactory private static SessionFactory factory; // ThreadLocal variables used to store objects ThreadLocalSession private static final ThreadLocal sessionContext = new ThreadLocal ( ); Static {init (); private static final void init () {try {config = new Configuration () configure ();. factory = config.buildSessionFactory ();} catch (HibernateException ex) {ex.printStackTrace (System.err); config = null; factory = NULL;}} Public static session OpenSession () throws hibernateException {session session = (session) sessionContext.get (); if (session == null) {session = factory.opensesis (); sessionContext.set (session);} returnction;} Public static void closesession () throws hibernateException {session session = (session) sessionContext.get (); sessionContext.set (null); if (session! = null) {session.close ();} Public static configuration getconfig () {return config;} PUBLIC STATIC sessionFactory getFactory () {return factory;}} After with Threadlocalsion, I can do photos.java, albums.java. Photos.java: Package annhy.photo.domains; Import java.util. *; Import Annhy.photo.hibort net.sf.hibernate. *; / ** * Used to process the relevant Static Funel of Photo. * @Author Annhy * @version 1.0, 2003/10/01 * / public class photos {/ ================== // == Finder methods // = ================= Public static Photo FindBypk (long id) throws hibernateException {return FindBypk (New long (id));} public static Photo findByPK (Long id) throws HibernateException {Session s = ThreadLocalSession.openSession (); Photo result = (Photo) s.load (Photo.class, id); ThreadLocalSession.closeSession (); return result;} public static Collection findAll () throws HibernateException {Session s = ThreadLocalSession.openSession (); Collection result = s.find ( "from" Photo.class.getName () "photo order by photo.id"); ThreadLocalSession.closeSession (); Return result;}}} Albums.java: Package annhy.photo.domains; Import java.util. *; Import Annhy.photo.hibort net.sf.hibernate. *; / ** * Used to process the relevant Static Versions of Album. * @Author Annhy * @version 1.0, 2003/10/01 * / public class albums {// =================== // == Finder methods // = ================= Public static album FindBypk (long id) throws hibernateException {Return FindBypk (new long (id));} public static album findbypk (long id) throws hibernateException { Session s = threadlocalSession (); album result = (album) s.load (album.class, id); threadlocalSession.CloseSession (); return result;} public static Collection findAll () throws HibernateException {Session s = ThreadLocalSession.openSession (); Collection result = s.find ( "from" Album.class.getName ()); ThreadLocalSession.closeSession (); return result;}} Current file list: /nnhy/photo/domains/Album.java /annhy/photo/domains/albums.java /anhy/photo/domains/photo.java /annhy/photo/domains/photos.java / annibains/photos.java / annies / photo / hibernate /Threadlocalsion.java /Hibernate.properties / Nannhy/photo/domains/photo.hbm.xml /annhy/photo/domains/album.hbm.xml ============================================================================================================================================================================================================= =============================== Use Hibernate to generate a corresponding database Now you can finally establish a database and add your test information. PHOTOTESTER.JAVA: Package annhy.photo; import annhy.photo.domains. *; import annhy.photo.hibort net.sf.hibernate. *; import.sf.hibernate.tool.hbm2ddl. *; Public class phototester {public static void main (String [] args) throws hibernateException {// Generate Database Schema Script files and establishes database generatedbschemascript (TRUE); // Establish test data inserttestdata (); // Query test data assert albums.findall (). Size () == 8: "There should be 8 album"; assert photos.Findall (). Size () == 3: "There should be 3 photo"; askERT Photos.FindBypk (1) .GETALBUMS (). Size () == 1: "Photo 1 belongs to 1 album"; assert photos.FindBypk (3) .Getalbums (). Size () == 2: "Photo 3 belongs to 2 albums "; public static void generateDbSchemaScript (boolean affectToDb) throws HibernateException {SchemaExport dbExport = new SchemaExport (ThreadLocalSession.getConfig ()); dbExport.setOutputFile ( "Photo_DB_Schema.sql"); dbExport.create (false, affectToDb);} Public static void inserttestdata () throws hibernateException {session s = threadlocalsion.openSession (); transaction t = s.begintransaction (); // crete all catalog objects album [] c = new album [8]; c [0] = new album ("My Album"); C [1] = New Album ("Family"); C [2] = New Album ("Student Age"); C [3] = New Album ("Other"); C [4] = New Album ("Dear Wife"); C [5] = New Album ("Baby Daughter "); C [6] = new album (" University "); C [7] = New Album (" Institute "); for (int i = 0; i // Create The Catalog Hierarchy C [0] .addchild (C [1]); C [0] .addchild (C [2]); C [0] .addchild (C [3]); C [1]. AddChild (C [4]); C [1] .addchild (C [5]); C [2] .addchild (C [6]); C [2] .addchild (C [7]); // The ROOT storage of the entire object network, all objects are divided into database S.Save (C [0]); // create all photo objects photo [] q = new photo [3]; q [0] = new photo ("c: //iMages/1.jpg"); Q [0] .Settitle ("University graduation photo !! "); Q [1] = new photo ("c: //images/2.jpg"); Q [1] .Settitle ("Research Graduation !!"); q [2] = new photo ("c: //images//3.jpg"); Q [2] .Settitle ("Baby Daughter Full Moon Maid"); For (int i = 0; i // Establish PHOTO and Album association C [6] .addphoto (q [0]); C [7] .addphoto (q [1]); Q [2] .addalbum (C [4]); Q [2] .addalbum (C [5]); // Return all objects S. Save (C [0]); // Transaction completion T.Commit (); threadlocalSession.Closesis ();}} The way to establish test data is very ugly. I don't know if there is any more good suggestion. However, pay attention to it, if there are two Domain Object to set the correlation (ex: obj1.addchild (obj2);), at least one of them must be deposited in DB with Hibernate, otherwise there will be Error. ============================================================================================================================================================================================================= =============================== If the author goes out, please don't have to wait patiently .. Now I finally understand the mood of the boy, the mood of the comic authors ... Because Jiang Lang did, I really want to hang a brand author out of picking materials, please don't have to wait patient, then disappear, avoid meeting ... this will not A very bad ... At present, I am still trying to understand Struts, and the work in my hand can't finish it. I will introduce you to a project that I found on SourceForge, Java struts-points http://sourceforge.net/projects/jpolls I am TRACE's code, it is much more skill (I abused me this new hand ...), interested can be discussed together. If it doesn't have a teaching document, or I discuss Thread can turn it off, and it will be connected to its teaching documents .... Not complete ... But, have time to say ...