分享

二维码Java开发(笔记)

 quasiceo 2014-11-13
分类: java 2014-07-01 13:42 136人阅读 评论(0) 收藏 举报
1、常见二维码码制

 
2、常用二维码:


 QR Code  PDF417 汉信码





3、常用二维码对比(QR、PDF417、DM、汉信码)


 

 

QR(日)

PDF417(美)

DM(韩)

汉信码(中)

备注

发明时间

 

1994年

1992年

1989年

2005年

 

是否中国国家标准

 

 

是否国际标准

 

 

面积

(mm*mm)

最小

21*21

90*9

10*10

有84个版本供自主选择,最小码仅有指甲大小

 

 

最大

177*177

853*270

144*144

 

 

信息存储量

 

最小

 

 

字节/平方英寸

2953(7%纠错信息)

1106(0.2%纠错信息)

1556(14%纠错信息)

4350

 

 

数字

4296

2710

3116

7829

 

 

字符

7089

1850

235

4350

 

 

汉字

1817

 

 

2174

 

 

二进制

2953

1556

 

3262

 

纠错能力

纠错分级

4级

9

非离散分级

4级

纠错能力越强,可以存储的有效信息越少

 

最高纠错信息

30%

46.20%

25%

30%

 

 

最低纠错信息

7%

0.20%

14%

8%

 

表示中文

 

一般

 

解码速度

 

一般

 

抗畸变、污损能力

 

较弱

一般

超强

 

识别方向性

 

全方向性

单方向

单方向

全方向性

 

识别设备

 

支持手机、PAD、摄像头

限专用设备

支持手机、PAD、摄像头

限专用设备

目前大部分手机二维码软件仅支持QR码



结论:上述资料中,最重要的一条“目前大部分手机二维码软件仅支持QR码”。所以,码制方式选用QR

4、QR码资。QRcode官网(中文):http://www./zh/

参考链接:http://kjah./blog/1567490  (楼主对该资料进行扩充及修改)

QR二维码是目前最常用二维码

是把字符串编码后通过二维图片的黑白两色模块显示出来

可表示的字符串长度和 容错率(ECC) 显示编码模式(EncodeMode)及版本(Version)有关

容错率共四档:

L 7%
M 15%
Q 25%
H 30%

注:7% --> 7%的字码可被修正。

QR码有容错能力,QR码图形如果有破损,仍然可以被机器读取内容,最高可以到7%~30%面积破损仍可被读取。

 编码模式:

Numeric             数字

Alphanumeric        英文字母

Binary              二进制

Kanji             汉字

版本(Version):

1-40 共40个版本

1       21x21模块

40     177x177模块

每增加一个版本每边增加4个模块 ,如: 版本2 为25x25模块

以下几张图片是字符串'www.sohu.com'的二维码使用了不同的版本的效果

 

 版本1   版本3    版本7  版本10 版本40



5、QR码具体java代码。


可以通过以下方法设置容错、编码模式、版本

setQrcodeErrorCorrect  L M Q H

setQrcodeEncodeMode      N数字 A英文 其他为Binary

setQrcodeVersion              不设置会自动选择适当的版本

这个库只是通过calQrcode方法返回表示二维码的数组,图像需要自己处理

boolean[][] s = testQrcode.calQrcode(d);


通过开源的java 程序生成二维码。

1、SwetakeQRCode 一个日本人写的。

2、google开源 ZXing。


参考链接:http://ylq365./blog/1160635


1)SwetakeQRCode Demo(创建二维码以及解析二维码):


需要的jar包:http://download.csdn.net/detail/wojiao555555/7578417


类:QRCodeSwetakeDemo.java

  1. package ljk.QRcode.swetake;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Graphics2D;  
  5. import java.awt.geom.AffineTransform;  
  6. import java.awt.image.BufferedImage;  
  7. import java.io.File;  
  8. import java.io.IOException;  
  9.   
  10. import javax.imageio.ImageIO;  
  11.   
  12. import jp.sourceforge.qrcode.QRCodeDecoder;  
  13. import jp.sourceforge.qrcode.exception.DecodingFailedException;  
  14.   
  15. import com.swetake.util.Qrcode;  
  16.   
  17. /** 
  18.  * 二维码生成demo 使用 swetake开源工具 
  19.  *  
  20.  * link:http://blog.csdn.net/wojiao555555/article/details/36184705  
  21.  */  
  22. public class QRCodeSwetakeDemo {  
  23.   
  24.     public static void main(String args[]) throws Exception{  
  25.           
  26.         String sms = "http://www.";  
  27.         String filePath = "C:\\Users\\Administrator\\Desktop\\QRcode124.png";  
  28.           
  29.         //QR码是正方形的,所以最好宽度和高度值相同  
  30.         int width = 500;  
  31.         int height = 500;  
  32.           
  33.         createrImage(sms, filePath, width, height);  
  34.           
  35.         String decodeMsg = decoderImage(filePath);  
  36.         System.out.println("二维码内容为:"+decodeMsg);  
  37.     }  
  38.   
  39.       
  40.     /** 
  41.      * 创建二维码 
  42.      *  
  43.      * @param sms_info  信息内容        如:www. 
  44.      * @param filePath  输出路径        如:"C:\\Users\\Administrator\\Desktop\\QRcode124.png" 
  45.      * @param width     宽度          生成二维码的宽度 
  46.      * @param height    高度          生成二维码的高度 
  47.      * @throws Exception 
  48.      */  
  49.     public static void createrImage(String sms_info,String filePath,int width,int height) throws Exception {  
  50.         try {  
  51.             Qrcode testQrcode = new Qrcode();  
  52.             testQrcode.setQrcodeErrorCorrect('M');//设置错误容错率     L(7%) M(15%) Q(25%) H(30%)    
  53.             testQrcode.setQrcodeEncodeMode('B');//设置编码模式    N数字 A英文 其他为Binary (设置为A的时候生成的二维码异常)  
  54.             testQrcode.setQrcodeVersion(7);//设置版本 (1~40)  
  55.             String testString = sms_info;  
  56.             byte[] d = testString.getBytes("UTF-8");  
  57.             System.out.println("信息编码后长度:"+d.length);  
  58.   
  59.             // 限制最大字节数为120。容错率、编码模式、版本 这几个参数决定了这个二维码能存储多少字节。  
  60.             if (d.length > 0 && d.length < 120) {  
  61.                 boolean[][] s = testQrcode.calQrcode(d);  
  62.                 BufferedImage bi = new BufferedImage(s.length, s[0].length,  
  63.                         BufferedImage.TYPE_BYTE_BINARY);  
  64.                 Graphics2D g = bi.createGraphics();  
  65.                 g.setBackground(Color.WHITE);  
  66.                 g.clearRect(00, s.length, s[0].length);  
  67.                 g.setColor(Color.BLACK);  
  68.                 int mulriple=1// 1像素  
  69.                 for (int i = 0; i < s.length; i++) {  
  70.                     for (int j = 0; j < s.length; j++) {  
  71.                         if (s[j][i]) {  
  72.                             g.fillRect(j * mulriple, i * mulriple, mulriple, mulriple);  
  73.                         }  
  74.                     }  
  75.                 }  
  76.                 g.dispose();//释放此图形的上下文以及它使用的所有系统资源。调用 dispose 之后,就不能再使用 Graphics 对象。  
  77.                 bi.flush();  
  78.                 File f = new File(filePath);  
  79.                 if (!f.exists()) {  
  80.                     f.createNewFile();  
  81.                 }  
  82.                   
  83.                 // 图像缩放  
  84.                 bi=resize(bi,width,height);  
  85.                   
  86.                 // 创建图片  
  87.                 ImageIO.write(bi, "png", f);  
  88.             }else {  
  89.                 System.out.println("信息编码后长度过长,请升高版本值(比如 testQrcode.setQrcodeVersion(10)),或降低容错率(比如:testQrcode.setQrcodeErrorCorrect(L))");  
  90.             }  
  91.         }  
  92.         catch (Exception e) {  
  93.             e.printStackTrace();  
  94.         }  
  95.           
  96.     }  
  97.       
  98.      /**   
  99.      * 图像缩放   
  100.      * @param source   
  101.      * @param targetW   
  102.      * @param targetH   
  103.      * @return   
  104.      */  
  105.     public static BufferedImage resize(BufferedImage source, int targetW,  
  106.             int targetH) {  
  107.         int type = source.getType();  
  108.         BufferedImage target = null;  
  109.         double sx = (double) targetW / source.getWidth();  
  110.         double sy = (double) targetH / source.getHeight();  
  111.         target = new BufferedImage(targetW, targetH, type);  
  112.         Graphics2D g = target.createGraphics();  
  113.         g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));  
  114.         g.dispose();  
  115.         return target;  
  116.     }  
  117.       
  118.     /** 
  119.      * 解析二维码 
  120.      * @param imgPath   二维码路径 
  121.      * @return          二维码内容 
  122.      */  
  123.     public static String decoderImage(String imgPath){  
  124.         File imageFile = new File(imgPath);  
  125.         BufferedImage bufImg = null;  
  126.         String content = null;  
  127.         try {  
  128.             bufImg = ImageIO.read(imageFile);  
  129.             QRCodeDecoder decoder = new QRCodeDecoder();    
  130.              content = new String(decoder.decode(new TwoDimensionCodeImage(bufImg)), "UTF-8");     
  131.         } catch (IOException e) {    
  132.             System.out.println("Error: " + e.getMessage());    
  133.             e.printStackTrace();    
  134.         } catch (DecodingFailedException dfe) {    
  135.             System.out.println("Error: " + dfe.getMessage());    
  136.             dfe.printStackTrace();    
  137.         }    
  138.         return content;    
  139.     }     
  140. }  

类:TwoDimensionCodeImage.java

  1. package ljk.QRcode.swetake;  
  2.   
  3. import java.awt.image.BufferedImage;  
  4.   
  5. import jp.sourceforge.qrcode.data.QRCodeImage;  
  6.   
  7. public class TwoDimensionCodeImage implements QRCodeImage {  
  8.   
  9.     BufferedImage bufImg;  
  10.       
  11.     public TwoDimensionCodeImage(BufferedImage bufImg) {  
  12.         this.bufImg = bufImg;  
  13.     }  
  14.       
  15.     @Override  
  16.     public int getHeight() {  
  17.         return bufImg.getHeight();  
  18.     }  
  19.   
  20.     @Override  
  21.     public int getPixel(int x, int y) {  
  22.         return bufImg.getRGB(x, y);  
  23.     }  
  24.   
  25.     @Override  
  26.     public int getWidth() {  
  27.         return bufImg.getWidth();  
  28.     }  
  29.   
  30. }  


生成的二维码:

尺寸:500 X 500 像素。



2)ZXingQRCode Demo(创建二维码以及解析二维码):


优点:


qrcode有1-40个version

version愈大,容错越高,像素愈多
qrcode的api把version给屏蔽掉了。
 
它自己根据输入的文字量和容错级别,
算出来需要多少bit来存数据。
然后循环所有的version,
看哪个能放下这么多字,就用哪个version。
这样的话,优势是生成的qrcode一直最小。

一个牛掰的作者生成的二维码链接:http://blog.csdn.net/kimmking/article/details/8244552


参考链接:http://blog.csdn.net/yangdong0906/article/details/8558871

ZXing jar包获取步骤:http://blog.csdn.net/chonbj/article/details/17913577

http://www.cnblogs.com/tankaixiong/archive/2010/10/31/1865807.html

jar包简化:http://www.cnblogs.com/keyindex/archive/2011/06/08/2074900.html




需要的jar包:http://download.csdn.net/detail/wojiao555555/7606799

类:QRCodeZXingDemo.java

  1. package ljk.QRcode.ZXing.ok;  
  2.   
  3. import java.awt.Graphics2D;  
  4. import java.awt.image.BufferedImage;  
  5. import java.io.File;  
  6. import java.io.IOException;  
  7. import java.util.Hashtable;  
  8.   
  9. import javax.imageio.ImageIO;  
  10.   
  11. import ljk.QRcode.ZXing.addImage.MatrixToImageConfigEx;  
  12. import ljk.QRcode.ZXing.addImage.MatrixToImageWriterEx;  
  13.   
  14. import com.google.zxing.BarcodeFormat;  
  15. import com.google.zxing.EncodeHintType;  
  16. import com.google.zxing.MultiFormatWriter;  
  17. import com.google.zxing.WriterException;  
  18. import com.google.zxing.client.j2se.MatrixToImageWriter;  
  19. import com.google.zxing.common.BitMatrix;  
  20. import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;  
  21.   
  22. /** 
  23.  * @Description 二维码demo 包含生成、解析、生成带logo图片的二维码。 
  24.  * @version 1.0 2014-07-03 
  25.  * @author LJK 
  26.  */  
  27. public class QRCodeZXingDemo {  
  28.     public QRCodeZXingDemo() {}  
  29.       
  30.     /** 
  31.      * @Title: createQRCode  
  32.      * @Description: 生成二维码图片 
  33.      * @param @param content        二维码文字内容 
  34.      * @param @param width          二维码图片宽度 
  35.      * @param @param height         二维码图片高度 
  36.      * @param @param imageSavePath  二维码图片保存路径 
  37.      * @param @param imgFormat      二维码图片格式, jpg/png 等 
  38.      * @param @throws IOException 
  39.      * @return void 
  40.      * @throws 
  41.      */  
  42.     public void createQRCode(String content, int width, int height, String imageSavePath, String imgFormat) throws IOException{  
  43.         Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();  
  44.         hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");  
  45.           
  46.         //指定错误纠正级别  共四个级别:  
  47.         /* 
  48.             L       7% 
  49.             M       15%  
  50.             Q       25%  
  51.             H       30%     
  52.          */  
  53.         hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); //互联网应用二维码不会破损,L容错即可,易识别  
  54.         BitMatrix matrix = null;  
  55.         try {  
  56.             //BarcodeFormat.QR_CODE:设置条行码类型  
  57.             /* 
  58.                 支持如下几种条形码 
  59.                 public static final BarcodeFormat AZTEC; 
  60.                 public static final BarcodeFormat CODABAR; 
  61.                 public static final BarcodeFormat CODE_39; 
  62.                 public static final BarcodeFormat CODE_93; 
  63.                 public static final BarcodeFormat CODE_128; 
  64.                 public static final BarcodeFormat DATA_MATRIX; 
  65.                 public static final BarcodeFormat EAN_8; 
  66.                 public static final BarcodeFormat EAN_13; 
  67.                 public static final BarcodeFormat ITF; 
  68.                 public static final BarcodeFormat MAXICODE; 
  69.                 public static final BarcodeFormat PDF_417; 
  70.                 public static final BarcodeFormat QR_CODE; 
  71.                 public static final BarcodeFormat RSS_14; 
  72.                 public static final BarcodeFormat RSS_EXPANDED; 
  73.                 public static final BarcodeFormat UPC_A; 
  74.                 public static final BarcodeFormat UPC_E; 
  75.                 public static final BarcodeFormat UPC_EAN_EXTENSION; 
  76.              */  
  77.             matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);  
  78.             writeToFile(matrix, imgFormat, imageSavePath);  
  79.         } catch (WriterException e) {  
  80.             e.printStackTrace();  
  81.         }  
  82.     }  
  83.       
  84.     /** 
  85.      * @Title: createQrCode  
  86.      * @Description: 生成二维码图片,并添加 logo (logo自动缩放为 二维码图片的 1/4大小)【注意】尽量不要使用黑白logo,影响识别。 
  87.      * @param @param content        二维码内容 
  88.      * @param @param width          二维码宽度 
  89.      * @param @param height         二维码高度 
  90.      * @param @param imageSavePath  二维码保存路径 
  91.      * @param @param imgFormat      二维码图片格式, jpg/png 等 
  92.      * @param @param logoPath       logo 路径 
  93.      * @return void 
  94.      * @throws 
  95.      */  
  96.     public void createQrCode(String content, int width, int height, String imageSavePath, String imgFormat, String logoPath){  
  97.         Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();  
  98.         hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");  
  99.         hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //之后要破坏图片添加logo,所以容错率调高(H),防止不能识别。  
  100.           
  101.         BitMatrix matrix = null;  
  102.         try {  
  103.             matrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);  
  104.             writeToFile(matrix, imgFormat, imageSavePath, logoPath);  
  105.         } catch (WriterException e) {  
  106.             e.printStackTrace();  
  107.         }  
  108.     }  
  109.   
  110.     /** 
  111.      * @Title: writeToFile  
  112.      * @Description: 写出二维码到磁盘,包含logo 
  113.      * @param @param matrix         二维码 bit矩阵 
  114.      * @param @param imgFormat      二维码图片格式, jpg/png 等 
  115.      * @param @param imageSavePath  二维码保存路径 
  116.      * @param @param logoPath       logo 路径 
  117.      * @return void 
  118.      * @throws 
  119.      */  
  120.     public void writeToFile(BitMatrix matrix, String imgFormat,String imageSavePath, String logoPath) {  
  121.         try {  
  122.             //写出图片  
  123.             BufferedImage image = writeToFile(matrix, imgFormat, imageSavePath);  
  124. //          //添加logo  
  125.             MatrixToImageWriterExtend.overlapImage(image, imageSavePath, logoPath, imgFormat);  
  126.         } catch (IOException e) {  
  127.             e.printStackTrace();  
  128.         }  
  129.     }  
  130.   
  131.     /** 
  132.      * @Title: writeToFile  
  133.      * @Description: 写出图片到磁盘 
  134.      * @param @param matrix         二维码 bit 矩阵 
  135.      * @param @param imgFormat      二维码图片格式,jpg/png 等 
  136.      * @param @param imageSavePath  二维码保存路径 
  137.      * @param @throws IOException    
  138.      * @return BufferedImage        二维码缓存 
  139.      * @throws 
  140.      */  
  141.     public BufferedImage writeToFile(BitMatrix matrix, String imgFormat,  
  142.             String imageSavePath) throws IOException {  
  143.         File file = new File(imageSavePath);  
  144.         BufferedImage image = MatrixToImageWriterExtend.writeToFile(matrix, imgFormat, file);  
  145.         return image;  
  146.     }  
  147.       
  148.     /** 
  149.      * @Title: main  
  150.      * @Description: 测试 
  151.      * @param @param args 
  152.      * @return void 
  153.      * @throws 
  154.      */  
  155.     public static void main(String[] args) {  
  156.         String content = "http://www.";  
  157.         String imageSavePath = "C:/Users/Administrator/Desktop/testode.png";  
  158.         String logoPath = "C:/Users/Administrator/Desktop/logo2.jpg";  
  159.         String imgFormat = "png";  
  160.         int width = 200;  
  161.         int height = 200;  
  162.           
  163.         QRCodeZXingDemo qrCode = new QRCodeZXingDemo();  
  164.         try {  
  165.             //写出二维码  
  166. //          qrCode.createQRCode(content, width, height, imageSavePath, imgFormat);  
  167.             //写出带logo 的二维码  
  168.             qrCode.createQrCode(content, width, height, imageSavePath, imgFormat, logoPath);  
  169.         } catch (Exception e) {  
  170.             e.printStackTrace();  
  171.         }  
  172.     }  
  173. }  


类:MatrixToImageWriterExtend.java

  1. package ljk.QRcode.ZXing.ok;  
  2.   
  3. import java.awt.Graphics2D;  
  4. import java.awt.image.BufferedImage;  
  5. import java.io.File;  
  6. import java.io.IOException;  
  7. import java.io.OutputStream;  
  8.   
  9. import javax.imageio.ImageIO;  
  10.   
  11. import com.google.zxing.common.BitMatrix;  
  12.   
  13. /** 
  14.  * @ClassName: MatrixToImageWriterExtend 
  15.  * @Description: 继承源代码中 MatrixToImageWriter 类,但该类是final的。所以把方法全部取出构建该类。 
  16.  * @author LJK 
  17.  * @date 2014-7-7 下午12:17:50 
  18.  * 
  19.  */  
  20. public class MatrixToImageWriterExtend {  
  21.       
  22.     private static final int BLACK = 0xFF000000;  
  23.     private static final int WHITE = 0xFFFFFFFF;  
  24.   
  25.     private MatrixToImageWriterExtend() {  
  26.     }  
  27.   
  28.     public static BufferedImage toBufferedImage(BitMatrix matrix) {  
  29.         int width = matrix.getWidth();  
  30.         int height = matrix.getHeight();  
  31.         BufferedImage image = new BufferedImage(width, height,  
  32.                 BufferedImage.TYPE_INT_RGB);  
  33.         for (int x = 0; x < width; x++) {  
  34.             for (int y = 0; y < height; y++) {  
  35.                 image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);  
  36.             }  
  37.         }  
  38.         return image;  
  39.     }  
  40.   
  41.     /** 
  42.      * @Title: writeToFile  
  43.      * @Description: ZXing 的源代码,只不过把 BufferedImage 对象返回了。 
  44.      * @param @param matrix 
  45.      * @param @param format 
  46.      * @param @param file 
  47.      * @param @return 
  48.      * @param @throws IOException 
  49.      * @return BufferedImage 
  50.      * @throws 
  51.      */  
  52.     public static BufferedImage writeToFile(BitMatrix matrix, String format, File file)  
  53.             throws IOException {  
  54.         BufferedImage image = toBufferedImage(matrix);  
  55.         if (!ImageIO.write(image, format, file)) {  
  56.             throw new IOException("Could not write an image of format "  
  57.                     + format + " to " + file);  
  58.         }  
  59.         return image;  
  60.     }  
  61.       
  62.     /** 
  63.      * @Title: overlapImage  
  64.      * @Description:    二维码添加自定义logo(关键部分) 
  65.      * @param @param image          二维码缓存 
  66.      * @param @param imgSavePath    二维码保存路径 
  67.      * @param @param logoPath       logo 路径 
  68.      * @param @param formate        二维码图片格式,jpg/png 等 
  69.      * @return void 
  70.      * @throws 
  71.      */  
  72.     public static void overlapImage(BufferedImage image, String imgSavePath, String logoPath, String formate) {  
  73.         try {  
  74.             BufferedImage logo = ImageIO.read(new File(logoPath));  
  75.               
  76.             Graphics2D g = image.createGraphics();  
  77.             // logo宽高  
  78.             double logoWidth = logo.getWidth();  
  79.             double logoHeight = logo.getHeight();  
  80.               
  81.             //logo 等比缩放  
  82.             while(logoWidth>image.getWidth()/2.5){  
  83.                 logoWidth /= 1.25;  
  84.                 logoHeight /= 1.25;  
  85.             }  
  86.               
  87.             int width = (int)logoWidth;  
  88.             int height = (int)logoHeight;  
  89.               
  90.             // logo起始位置,此目的是为logo居中显示  
  91.             int x = (image.getWidth() - width) / 2;  
  92.             int y = (image.getHeight() - height) / 2;  
  93.             g.drawImage(logo, x, y, width, height, null);  
  94.             g.dispose();  
  95.             ImageIO.write(image, formate, new File(imgSavePath));  
  96.         } catch (Exception e) {  
  97.             e.printStackTrace();  
  98.         }  
  99.     }  
  100.   
  101.     public static void writeToStream(BitMatrix matrix, String format,  
  102.             OutputStream stream) throws IOException {  
  103.         BufferedImage image = toBufferedImage(matrix);  
  104.         if (!ImageIO.write(image, format, stream)) {  
  105.             throw new IOException("Could not write an image of format "  
  106.                     + format);  
  107.         }  
  108.     }  
  109. }  



生成的二维码:

尺寸:500 X 500 像素。

注意:ZXing 生成的二维码是有白边的,并且生成图像哪块代码不用自己写,很方便。



完事了~~


上述demo的地址:http://download.csdn.net/detail/wojiao555555/7606829



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约