Das Schreiben einer Java -Version von Simple Cloud -Album, die implementierten Funktionen sind:
Benutzer können jeweils eine in mehrere Dateien hochladen.
Benutzer können Bilder herunterladen, die von anderen hochgeladen wurden.
Benutzer können Bilder von allen anderen anzeigen.
Benutzer können nur Bilder löschen, die über ihre eigene IP hochgeladen wurden.
Verwendete Techniken:
Datei -Upload und Download, Designmodus, DOM4J, XPath usw.
Schauen wir uns die nächsten beiden Seiten an:
Quellcode:
web.xml:
<? xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <display-name></display-name> <servlet> <servlet-name>UploadServlet</servlet-name> <servlet-class>cn.hncu.servlets.UploadServlet</servlet-class> </servlet> <servlet> <servlet-name>cloudPhotoServlet</servlet-name> <servlet-class>cn.hncu.servlets.cloudPhotoServlet</servlet-class> </servlet> <servlet> <servlet-name>DownServlet</servlet-name> <servlet-class>cn.hncu.servlets.DownServlet</servlet-class> </servlet> <servlet> <servlet-name>DelServlet</servlet-name> <servlet-class>cn.hncu.servlets.DelServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadServlet</servlet-name> <url-pattern>/upload</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>cloudPhotoServlet</servlet-name> <url-pattern>/cloudPhoto</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-mapping> <servlet-name>DownServlet</servlet-name> <URL-Muster>/Servlet/DownServlet </url-pattern> </Servlet-Mapping> <Servlet-Mapping> <Servlet-Name> Delservlet </Servlet-NAME> <URL-PATTERN>/Servlet/Delservlet </url-pattern> </servlet-maping> <Welcome-file-list> <Welcome-file-file> </Welcome-file-list> </Welcome-file-file> </[Begrüßungsliste> </Welcome-file> </[Begrüßungsliste> </Begrüßungsliste> Index> </[Begrüßungsliste> <Welclode-file> < </Welcome-File-List> </web-App>
index.jsp:
<%@ page Language = "java" import = "java.util. input.Parentelement.Parentelement.Parentelement; // Tabelle.NoDename tbody table.removechild (input.Parentelement.Parentelement); } var t = 1; Funktion addfile (input) {tr = input.Parentelement.Parentelement; //alert(tr.nodename); var str = "<Td> Datei auswählen: </td>"+ "<td> <Eingabe type = 'Datei' name = 'Datei"+ t+ "'> </td>"+ "<td> Dateibeschreibung: </td>"+ "<td> <Eingabe type = 'Text' name = 'text"+ t+ ". Onclick = 'Delfile (this)'> </td> "; tr.insertadjacentHtml ("vorabgin", str); } function move () {window.location.href = "/myphoto/cloudphoto"; } </script> <style type = "text/css"> #font {color: rot; } </style> </head> <body> <h1><font id="font"> Album upload: </font></h1> <form action="/myPhoto/upload" method="post" enctype="multipart/form-data"> <table> <tr> <td>Select file: </td> <td> <input type="file" name="file1"> </td> <td> File description: </td> <td> <input type="text" name="text1"> </td> <td> <input type="button" value="delete file" onclick="delFile(this)"> </td> </tr> <tr> <td colspan=2> <input type="submit" value="upload file"> </td> <td colspan=3> <input type = "button" value = "Datei hinzufügen" onclick = "addFile (this)"> </td> </tr> </table> </form> <form action = "/myphoto/cloudPhoto" methode = "post" Encttype = "MultiPart/Form-Data"> <table> <tr> <Td Colspan = 5> <Input type = "Value". onclick = "move ()"> </td> </tr> </table> </form> </body> </html>foto.xml:
<? xml Version = "1.0" coding = "utf-8"?> <fotos> </fotos>
Myutils.java:
Paket cn.hncu.utils; import Java.Text.SimpledateFormat; Import java.util.date; import Java.util.UUID; } / ** * @param uUid * @return den kaputten Pfad durch uUid * / public static String getDir (String uUid) {String dir1 = Integer.tohexString (uUid.hashCode () & 0xf); String dir2 = Integer.tohexString ((uUid.hashCode () & 0xf0) >> 4); return "/"+dir1+"/"+dir2; } // Datumszeitformat private statische SimpleDateFormat sdf = new SimpledateFormat ("Yyyyy Year Mm Monat DD DATUM HH: MM: SS"); / *** @Return gibt das Datum und die Uhrzeit beim Hochladen von*/ public static String GetCurrentDatetime () {return sdf.format (neuer Datum ()) zurück; }}Dom4JFactory.java:
Paket cn.hncu.utils; import Java.io.fileinputstream; Import Java.io.FilenotFoundException; Import Java.io.FileOutputStream; Java.io.ioxception; org.dom4j.element; import org.dom4j.node; import org.dom4j.io.saxreader; import org.dom4j.io.xmlwriter; öffentliche Klasse DOM4JFactory {private static document dom = null; privater statischer Saitenpfad; // statischer Block! Wird nur einmal laufen! Das Merkmal ist, dass wenn die Klasse geladen ist, statisch {try {saxreader sax = new Saxreader () ausgeführt wird; // Da unsere Ressourcen von Myelipse zum Tomcat -Server veröffentlicht wurden, unterscheidet sich dies vom ursprünglichen Pure Java -Projekt. // Verwenden Sie die aktuelle Klasse, um ihren Klassenlader zu finden, und erhalten Sie dann den Ressourcenpfad über den Klassenlader. path = Dom4JFactory.class.getClassloader (). getResource ("foto.xml"). getPath (); // GetClassloader () zurückgibt: Laden des Klassenladers der Klasse oder Schnittstelle, das durch dieses Objekt dargestellt wird // öffentliche URL getResource (String -Name) zurückgibt: Lesen Sie das URL -Objekt der Ressource; Wenn die Ressource nicht gefunden werden kann oder der Anrufer nicht genügend Erlaubnis hat, die Ressource zu erhalten, geben Sie NULL zurück. // Diese Methode sucht zunächst nach dem übergeordneten Klassenlader der Ressource. Wenn der Lader der Elternklasse null ist, ist der Suchpfad der Pfad des integrierten Klassenladers der virtuellen Maschine. // Public String getPath () erhält den Pfadteil dieser URL. System.out.println (Path); DOM = SAX.Read (neuer FileInputStream (Pfad)); } catch (FilenotFoundException e) {neue runTimeexception (e) werfen; } catch (documentException e) {neue runTimeexception (e) werfen; }} / ** * @return das Dokument des Albums * / public static document getDocument () {return dom; } / ** * foto.xml speichern und auf lokal speichern * / public static boolean save () {try {xmlwriter w = neuer xmlwriter (neuer FileOutputStream (Pfad)); W.Write (DOM); W.CLOSE (); zurückkehren; } catch (unportedenCodingException e) {return false; } catch (FilenotFoundException e) {return false; } catch (ioException e) {return false; }} public static boolean del (string uUid) {node node = dom.selectsinglenode ("[@uuid = '"+uUid+"']"); if (node == null) {return false; } node.getParent (). Remove (Knoten); zurückkehren; } / *** test* @param args* / public static void main (string [] args) {System.out.println (getDocument ()); }}Photomodel.java - Wertobjekt
Paket cn.Hncu.domain;/*** Value-Objekt-Kapselung* @Author Chen Haoxiang* 2016-7-24*/Public Class Photomodel {private String uUid; // Uuid private String Realname = ""; // Der Bildname des Bildnamens (Dateiname ", wenn private string ext; Datei private Zeichenfolge IP; // Der IP -private String des Uploaders des Uploaders Desc; // Die Dateibeschreibung public String getuUid () {return UUID; } public void setUuid (String uUid) {this.uUid = uUid; } public String getRealName () {return RealName; } public void setRealName (String RealName) {this.realName = realName; } public String getext () {return ext; } public void setext (string ext) {this.ext = ext; } public String getDir () {return dir; } public void setDir (String dir) {this.dir = dir; } public String getDatetime () {return dateTime; } public void setDateTime (String datetime) {this.datetime = datetime; } public String getiP () {return ip; } public void setIp (String ip) {this.ip = ip; } public String getDesc () {return desc; } public void setDesc (String Desc) {this.desc = desc; } @Override public String toString () {return "photoModel [uUid =" + uUid + ", realname =" + realname + ", ext =" + ext + ", Dir =" + Dire + ", DateTime =" + DateTime + ", ip =" + ip + ", Desc =" + "]"; }}Fotodao.java:
Paket cn.hncu.photodao.dao; import Java.util.List; importieren cn.hncu.domain.photomodel; public interface photodao { / *** @param foto* @return Save Data* / public boolean speichern (motomodel photo); / *** @Return gibt alle Bildinformationen zurück*/ publiclist <Profotomodel> getAll (); / *** @param uUid* @return das eingekapselte Wertobjekt über uUid*/ public Photomodel GetinglebyUuid (String uUid); / ** * @param uUid * @return die Informationen des Bildes in fotos.xml durch uUid */ public boolean deletexml (String uUid); / ** * @param dir * @return die Informationen des Bildes in der Serverscheibe über den Pfad */ public boolean deleteFile (String pathFileName);};};Fotoserimpl.java:
Paket cn.hncu.photodao.impl; import Java.io.file; import Java.util.ArrayList; Import Java.util.iterator; import Java.util.list; import org.dom4j.document; cn.hncu.photodao.dao.photodao; import cn.hncu.utils.dom4jfactory; öffentliche Klasse fotoserimpl implementiert photodao {@Override public boolean save (Photomodel photo) {document dom4jfactory.getDocument (); Element root = dom.getrootelement (); // Attributelement p = root.addelement ("foto") hinzufügen; p.addattribute ("uUid", foto.getuUid ()); p.addattribute ("Realname", foto.getRealName ()); p.addattribute ("DateTime", foto.getDatetime ()); p.addattribute ("IP", foto.getIp ()); p.addattribute ("ext", foto.getext ()); p.addattribute ("Dir", foto.getDir ()); p.addattribute ("Desc", foto.getDesc ()); return dom4JFactory.save (); } @Override öffentliche Liste <Photomodel> getAll () {list <Photomodel> list = new ArrayList <Potomodel> (); Document dom = dom4jfactory.getDocument (); Element root = dom.getrootelement (); Iterator <element> it = root.elementiterator ("foto"); // Holen Sie sich den Iterator des Fotoelements über DOM4J, und Sie können auch alle Fotos über XPath // List <node> lists = Dom.Selectnodes ("// foto [@uuid]") finden; // iterator <node> it = lists.iterator (); while (it.hasnext ()) {Element e = it.next (); Photomodel photo = new Photomodel (); foto.setuuid (e.attributeValue ("uUid")); foto.setRealName (e.attributeValue ("Realname")); foto.setDatetime (e.attributeValue ("datetime")); foto.setext (e.attributeValue ("ext")); foto.setip (e.attributeValue ("ip")); foto.setDir (e.attributeValue ("dir")); foto.setDesc (e.attributeValue ("Desc")); list.add (Foto); } Rückgabeliste; } @Override public Photomodel GetSinglebyUuid (String uUid) {list <Potomodel> fotos = getAll (); für (Photomodel Foto: fotos) {if (foto.getuUid (). Equals (uUid)) {return photo; }} return null; } @Override public boolean deletexml (string uUid) {document dom = dom4jfactory.getDocument (); Element e = (Element) dom.Selectsinglenode ("// foto [@uuid = '"+uUid.trim ()+"']"); return e.getParent (). entfernen (e); } @Override public boolean deleteFile (String pathFileName) {try {file = new Datei (pathFileName); if (file.exists ()) {file.delete (); } Return true; } catch (Ausnahme e) {return false; }}}Fotodaofactory.java:
package cn.hncu.photoDao.factory;import cn.hncu.photoDao.impl.PhotoSerImpl;/** * Factory method* @author Chen Haoxiang* 2016-7-24 */public class PhotoDaoFactory { public static PhotoSerImpl getPhotoDao(){ return new PhotoSerImpl(); }}UploadServlet.java:
Paket cn.hncu.servlets; import java.io.file; import java.io.ioxception; import Java.io.printwriter; import Java.util.list Javax.servlet.servlet.servlet.Servlet. javax.servlet.http.httpServletResponse; import org.apache.commons.FileUpload.FileItem; import org.apache.commons.FileUpload.FileUploadexception; import org.apache org.apache.commons.FileUpload.servlet.servletFileUpload; importieren cn.hncu.domain.photomodel; importieren cn.hncu.photodao.dao.photodao; Importory; cn.hncu.utils.myutils; öffentliche Klasse UploadServlet erweitert HttpServlet {public void dodget (httpServletRequest Request, httpServletResponse) löscht servletException, ioException {response.setContentType (text/html; charset = utf-8 "); response.getWriter (). print ("<h1> sorry, diese Seite unterstützt keinen Get Access !!! </h1>"); response.getWriter (). print ("<a href = 'javaScript: history.go (-1)'> zur vorherigen Seite zurückkehren </a>"); } public void dopost (httpServletRequest-Anforderung, httpServletResponse-Antwort) löst ServletException aus, iOException {response.setContentType ("text/html; charset = utf-8"); final printwriter out = response.getWriter (); // Anti-Black-Non-Multipart-Formularübermittlung // Verwenden Sie Upload-Tool Boolean Boo = servletFileUpload.ismultiPartContent (Anfrage); if (! boo) {out.print ("<h1> unterstützt die Einreichungsmethode der gewöhnlichen Formulare nicht! </h1>"); zurückkehren; } File file = new File ("d:/photocache"); if (! file.exists ()) {file.mkdir (); } DiskFileItemFactory fiFactory = new diskFileItemFactory (1024*10, Datei); ServletFileUpload upload = new ServletFileUpload (fifactory); upload.SetheaDerCoding ("utf-8"); // Dateiname codieren String path = getServletContext (). getRealPath ("/fotos"); FileItem fi = null; try {list <FileItem> list = upload.ParSerequest (Anfrage); Photomodel photo = new Photomodel (); // Datenkapselung --- 7 Eigenschaften sind erforderlich. int cont = 0; für (FileItem F: Liste) {if (cont! = 0 && cont%2 == 0 &&! foto.getRealName (). Equals ("")) {foto = new Photomodel (); // Neudata-Kapselung} fi = f; if (fi.isformfield ()) {// normale Formularkomponente // Dateibeschreibung String String Desc = fi.getString ("utf-8"); foto.setDesc (Desc); //#1} else {// Anti-Black 3- Wenn die Datei in der Dateikomponente nicht ausgewählt ist, wenn (fi.getSize () == 0) {photo.setRealName (""); cont ++; weitermachen; } String Dateiname = fi.getName (); fileName = Dateiname.substring (Dateiname.lastindexof ("//")+1); // Real Dateiname Foto.SetRealName (Dateiname); //#2 String ext = Dateiname. foto.setDatetime (myutils.getCurrentDateTime ()); //#4 foto.setip (request.getremoteaddr ()); //#5 String uUid = myutils.getuuid (); foto.setuUid (uUid); //#6 foto.setdir (myutils.getDir (uUid)); //#7 // Die Verzeichnisdatei dfile = neue Datei (Pfad+photo.getDir ()); if (! dfile.exists ()) {dfile.mkdir (); } fi.write (neue Datei (Pfad+foto.getDir ()+"/"+foto.getuUid ()+foto.getext ())); } cont ++; if (cont%2 == 0 &&! foto.getRealName (). Equals ("") {photodao dao = photodaofactory.getPhotodao (); Boo = Dao.Save (Foto); // Speichern auf Disk - Methode 2: FileUtils.copyInputStreamtoFile (in, neue Datei (Dateiname2)); // ※ 2 ※ Speichern Sie die Bilddatei auf dem Server -Festplatten -Foto = new Photomodel (); // Recapsulation}} catch (FileUploadexception e) {E.printstacktrace (); } catch (Ausnahme e) {e.printstacktrace (); } endlich {if (fi! = null) {fi.delete (); } if (dom4jfactory.save ()) {out.print ("<h1> erfolgreich hochgeladen! </h1>"); out.print ("<a href = 'javaScript: history.go (-1)'> zur vorherigen Seite zurückkehren </a>"); } else {out.print ("<h1> Upload fehlgeschlagen! </h1>"); out.print ("<a href = 'javaScript: history.go (-1)'> zur vorherigen Seite zurückkehren </a>"); }}}}Zeigen Sie alle Dateien -cloudphotoServlet.java an
Paket cn.hncu.servlets; import Java.io.ioException; import Java.io.printwriter; import Java.util.List; import Javax.servlet.servletException; importieren javax.servlet.http.httplet; import Javax.http.http.http.httpl. javax.servlet.http.httpServletResponse; importieren cn.hncu.domain.photomodel; importieren cn.hncu.photodao.dao.photodao import cn.hncu.photodao.factory.photodaofactory; public classes public classes cloudscletothotoservlet -stufte httpletory voidcassory; public Class CloudPhotoServlet -versteuert; DOGGE (httpServletRequest Request, httpServletResponse -Antwort) löst ServletException aus, ioException {String pwd = (String) request.getParameter ("pwd"); if ("chx" .equals (pwd)) {Dopost (Anfrage, Antwort); } else {response.setContentType ("text/html; charSet = utf-8"); Antwort.getWriter (). Print ("<h1> Entschuldigung, Sie haben keine Erlaubnis zum Zugriff !!! </h1>"); }} public void dopost (httpServletRequest-Anforderung, httpServletResponse-Antwort) löst ServletException aus, ioException {response.setContentType ("text/html; charset = utf-8"); Printwriter out = response.getWriter (); out.println ("<! docType html public/"-// w3c // dtd html 4.01 transitional // en/">"); out.println ("<html>"); out.println ("<Head> <title> CHX Cloud Album </title> </head>"); out.println ("<body>"); out.println ("<table border = '1px; double;#ff0000'>"); out.println ("<tr>"); out.println ("<tr>"); out.println ("<Td> Dateiname </td>"); out.println ("<td> Upload -Zeit"); out.println ("<td> Datei </td>"); out.println ("<td> Dateibeschreibung </td>"); out.println ("<td> operation </td>"); out.println ("</tr>"); String tdwh = "style = 'width: 200px; Höhe: 200px;'"; // Alle Bilder anzeigen fotodao dao = photodaofactory.getPhotodao (); Liste <Photomodel> fotos = dao.getall (); für (Photomodel Foto: Fotos) {String Dateiname = Foto.getRealName (); String time = photo.getDatetime (); // Ausgabe Bild String path = request.getContextPath () + "/fotos/" + foto.getDir () + "/" + foto.getuuid () + foto.getext (); // system.out.println (Path); // /myphoto/photos//7/c/a1237a48a6aa451cb22fa78b15bafcea.jpg String img = "<a href = '" + path + "'> <img Src = '" + Path + "'/> </a>"; String desc = photo.getDesc (); String delstr = "<a href = '/myphoto/servlet/delservlet? UUid =" + foto.getuuid () + "'> delete </a>"; String downstr = "<a href = '/myphoto/servlet/downservlet? Uuid =" + foto.getuuid () + "'> download </a>"; out.println ("<td" + tdwh + ">" + Dateiname + "</td>"); out.println ("<td" + tdwh + ">" + time + "</td>"); out.println ("<td" + tdwh + ">" + img + "</td>"); out.println ("<td" + tdwh + ">" + Desc + "</td>"); out.println ("<td" + tdwh + ">" + delstr + "" + downstr + "</td>"); out.println ("</tr>"); } out.println ("<tr>"); out.println ("</tr>"); out.println ("</table>"); out.println ("</body>"); out.println ("</html>"); out.flush (); out.close (); }}Datei löschen - delservlet.java
Paket cn.hncu.servlets; import Java.io.ioException; import Java.io.printwriter; import Javax.servlet.servletException; import Javax.servlet.http.httpserd; javax.servlet.http.httpServletResponse; importieren cn.hncu.domain.photomodel; importieren cn.hncu.photodao.dao.photodao import cn.hncu.photodao.factory.photodaofactory; public class -öffentlich klassifische DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet -DelServlet. Fotodaofactory.getPhotodao (); public void dodget (httpServletRequest Request, httpServletResponse -Antwort) löst ServletException aus, ioException {Dopost (Request, Antwort); } public void dopost (httpServletRequest -Anforderung, httpServletResponse -Antwort) löst ServletException aus, ioException {string uUid = request.getParameter ("uUid"); String ip = request.getRemoteaddr (); Antwort.SetContentType ("text/html; charSet = utf-8"); Printwriter out = response.getWriter (); Photomodel photo = dao.getSinglebyuuid (uUid); if (foto! out.print ("<a href = 'javaScript: history.go (-1)'> zur vorherigen Seite zurückkehren </a>"); zurückkehren ; } // 1. Informationen in der Datenbank boolean boo = dao.deletExml (uUid) löschen; if (boo) {String fileName = "fotos/"+foto.getDir ()+"/"+foto.getuUid ()+foto.getext (); String pathFileName = getServletContext (). GetRealPath (Dateiname); if (dao.deletefile (pathFileName)) {// Umleiten Sie die Album -Seite Antwort. } else {out.print ("<h1> kann nicht vom Server gelöscht werden, die Datei wird besetzt !!! </h1>"); out.print ("<a href = 'javaScript: history.go (-1)'> kehren Sie zur vorherigen Seite zurück </a>"); }} else {out.print ("<h1> Die Datei existiert nicht mehr !!! </h1>"); out.print ("<a href = 'javaScript: history.go (-1)'> kehren Sie zur vorherigen Seite zurück </a>"); }}}}Download Datei -Downservlet.java
Paket cn.hncu.servlets; import Java.io.FileInputStream; Import Java.io.ioException; import Java.io.inputstream; import Java.io.outputStream; importieren java.net.urlencoder; javax.servlet.http.httpServletRequest; import javax.servlet.http.httpserletResponse; importieren cn.hncu.domain.photomodel importieren cn.hncu.photodao.dao.photodao; DownServlet erweitert httpServlet {private photodao dao = photodaofactory.getPhotodao (); public void dodget (httpServletRequest Request, httpServletResponse -Antwort) löst ServletException aus, ioException {Dopost (Request, Antwort); } public void dopost (httpServletRequest -Anforderung, httpServletResponse -Antwort) löst ServletException aus, ioException {string uUid = request.getParameter ("uUid"); System.out.println (uUid); Photomodel photo = dao.getSinglebyuuid (uUid); System.out.println (Foto); if (foto! String realName = photo.getRealName (); String agent = request.getheader ("user-Agent"); System.out.println (Agent); if (Agent.Indexof ("Mozilla")! =-1) {// Firefox-Browser-Antwort. } else {// Lösen Sie das Problem des chinesischen Strichs (verwenden Sie einfach den folgenden Satz, um den Dateinamen zu codieren) RealName = urlencoder.encode (Realname, "UTF-8"); // Verwenden Sie den angegebenen Codierungsmechanismus, um die Zeichenfolge in die Anwendung/x-ww-form-rodeskodiertes Format zu konvertieren. response.setheader ("Inhaltsdisposition", "Anhang; Dateiname =/" "+Realname+"/""); // Hinweis: "Cttachment;" Kann nicht fehlen, andernfalls wird der Browser direkt in einem neuen Fenster geöffnet} String Dateiname = "fotos/"+foto.getDir ()+"/"+foto String pathFileName = getServletContext (). GetRealPath (Dateiname); InputStream in = new FileInputStream (PathFileName); OutputStream out = response.getOutputStream (); Byte buf [] = neues Byte [2048]; int len = 0; while ((len = in.read (buf))! =-1) {out.write (buf, 0, len); } out.close (); in.close (); } else {response.setContentType ("text/html; charSet = utf-8"); Antwort.getWriter (). println ("<h1> Diese Datei wurde </h1>") gelöscht; }}}Demonstrationsergebnisse
Ich werde das nicht demonstrieren, es stehen Bilder vor und ich habe alle Quellcodes gegeben. Wenn Sie interessiert sind, können Sie sich selbst verbessert.
In der Tat kann dies auch alle anderen Art von Dateien hochladen, da wir keinen schützenden Suffixnamen haben, und wir verwenden das Charakter -Streaming, um ihn zu übertragen, und es wird nicht verzerrt (es kann als Wolkenscheibe ~~ verarbeitet werden)! !
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.