基于struts2的二维码

前言

前段时间因为一些原因要做一个二维码,故此google了许多,当然是在踩了许多坑之后,找到了适合自己的方法,故在此将其总结一下,来提高自己

什么是二维码

总的来说就是用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息的;在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,最后通过相关设备读取。

zxing

zxing是google的一个开源源码,主要用于java生成和解析的条形码,二维码,通过引用相关jar包,实现其中的相关接口来开发,这里我引用的是QRCode.jar主要是生成二维码

需求案例

假设我们通过扫描二维码将数据库中的信息取出来并显示在另一个页面

环境准备

MyEclipse、mysql数据库(这里建了一张简单表,有id、name、password)、ssh整合包(事实上,我们可以单独使用struts2,只不过耗时一些),QRCode.jar包,jquery-1.8.3.js,gson.jar

二维码工具包

这里主要有三个类,一个是图像本身类(包含其本身一些属性)、二维码处理类(包括生成和解析图像二维码),最后一个是将本地图片通过调用处理类转化为二维码。
这里我将其放在com.zwl.util包下(以下是相关代码)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class QRCodeImageBean implements QRCodeImage{
BufferedImage bufImg;
public QRCodeImageBean(BufferedImage bufImg) {
this.bufImg = bufImg;
}
public int getHeight() {
return bufImg.getHeight();
}
public int getPixel(int x, int y) {
return bufImg.getRGB(x, y);
}
public int getWidth() {
return bufImg.getWidth();
}
}

生成和解析二维码类
public class QRCode {

 /**
 * 解析二维码(QRCode)
 * @param imgPath
 * @return content(返回二维码内容)
 */
public static  String decoderQRCode(String imgPath) {  
    // QRCode 二维码图片的文件  
    File imageFile = new File(imgPath);  
    BufferedImage bufImg = null;  
    String content = null;  
    try {  
        bufImg = ImageIO.read(imageFile);  
        QRCodeDecoder decoder = new QRCodeDecoder();  
        content = new String(decoder.decode(new QRCodeImageBean(bufImg)), "utf-8");   
    } catch (IOException e) {  
        System.out.println("Error: " + e.getMessage());  
        e.printStackTrace();  
    } catch (DecodingFailedException dfe) {  
        System.out.println("Error: " + dfe.getMessage());  
        dfe.printStackTrace();  
    }  
    return content;  
}  

/**  
 * 生成二维码(QRCode)图片  
 * @param content 存储内容  
 * @param imgPath 图片路径  
 * @param imgType 图片类型  
 */    
public static void encoderQRCode(String content, String imgPath, String imgType) {    
    encoderQRCode(content, imgPath, imgType, 7);    
}  

/**  
 * 生成二维码(QRCode)图片  
 * @param content 存储内容  
 * @param imgPath 图片路径  
 * @param imgType 图片类型  
 * @param size 二维码尺寸  
 */    
public static void encoderQRCode(String content, String imgPath, String imgType, int size) {    
    try {    
        BufferedImage bufImg = qRCodeCommon(content, imgType, size);    

        File imgFile = new File(imgPath);    
        // 生成二维码QRCode图片    
        ImageIO.write(bufImg, imgType, imgFile);    
    } catch (Exception e) {    
        e.printStackTrace();    
    }    
}  

/**  
 * 生成二维码(QRCode)图片的公共方法  
 * @param content 存储内容  
 * @param imgType 图片类型  
 * @param size 二维码尺寸  
 * @return  
 */    
private static BufferedImage qRCodeCommon(String content, String imgType, int size) {    
    BufferedImage bufImg = null;    
    try {    
        Qrcode qrcodeHandler = new Qrcode();    
        // 设置二维码排错率,可选L(7%)、M(15%)、Q(25%)、H(30%),排错率越高可存储的信息越少,但对二维码清晰度的要求越小    
        qrcodeHandler.setQrcodeErrorCorrect('M');    
        qrcodeHandler.setQrcodeEncodeMode('B');    
        // 设置设置二维码尺寸,取值范围1-40,值越大尺寸越大,可存储的信息越大    
        qrcodeHandler.setQrcodeVersion(size);    
        // 获得内容的字节数组,设置编码格式    
        byte[] contentBytes = content.getBytes("utf-8");    
        // 图片尺寸    
        int imgSize = 67 + 12 * (size - 1);    
        bufImg = new BufferedImage(imgSize, imgSize, BufferedImage.TYPE_INT_RGB);    
        Graphics2D gs = bufImg.createGraphics();    
        // 设置背景颜色    
        gs.setBackground(Color.WHITE);    
        gs.clearRect(0, 0, imgSize, imgSize);    

        // 设定图像颜色> BLACK    
        gs.setColor(Color.BLACK);    
        // 设置偏移量,不设置可能导致解析出错    
        int pixoff = 2;    
        // 输出内容> 二维码    
        if (contentBytes.length > 0 && contentBytes.length < 800) {    
            boolean[][] codeOut = qrcodeHandler.calQrcode(contentBytes);    
            for (int i = 0; i < codeOut.length; i++) {    
                for (int j = 0; j < codeOut.length; j++) {    
                    if (codeOut[j][i]) {    
                        gs.fillRect(j * 3 + pixoff, i * 3 + pixoff, 3, 3);    
                    }    
                }    
            }    
        } else {    
            throw new Exception("QRCode content bytes length = " + contentBytes.length + " not in [0, 800].");    
        }    
        gs.dispose();    
        bufImg.flush();    
    } catch (Exception e) {    
        e.printStackTrace();    
    }    
    return bufImg;    
}  }

最后一个类是本地生成二维码图片

1
2
3
4
5
6
7
public static void main(String[] args) {
String imgPath = "C:/Users/Administrator/Desktop/img/xiazi.jpg";
QRCode handler = new QRCode();
String qrCon = handler.decoderQRCode(imgPath);
String encoderContent = "http://192.168.43.44:100/librarytest/success1.jsp?id=2";
handler.encoderQRCode(encoderContent, imgPath, "png");
}

其中imgPath是本地你想将某个图片生成二维码的那个图片
qrCon为解析后的二维码内容,我这里就是一个url地址
encoderContent:设置二维码的内容,这里为url带个参数,扫描后就会跳转到相应界面
这里的参数想要取出,可以先将内容取出,在通过string类中的方法将字符创相应位置字符取出即可
至此,工具类算是有了,接下来就是结合具体配置

后台方法

首先是web.xml(启用struts2和spring)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app>

然后是applicationContext.xml(为了方便直接将所有方法都注入了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<!-- 定义数据源 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:msql端口/项目</value>
</property>
<property name="username">
<value>你的用户名</value>
</property>
<property name="password">
<value>你的密码</value>
</property>
</bean>
<!-- 定义SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>com/zwl/pojo/User.hbm.xml</value>
</list>
</property>
</bean>
<!-- 定义HibernateTemplate -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<!-- 配置DAO组件 -->
<bean id="returnuserdao" class="com.zwl.impl.returnuserdaoimpl">
<property name="hibernateTemplate">
<ref bean="hibernateTemplate"/>
</property>
</bean>
<!-- 配置业务逻辑组件 -->
<bean id="returnuserservice" class="com.zwl.impl.returnuserserviceimpl">
<property name="userdao">
<ref bean="returnuserdao"/>
</property>
</bean>
<!-- 配置userdengluAction -->
<bean id="userreturn" class="com.zwl.action.userreturn">
<property name="returnuser">
<ref bean="returnuserservice"/>
</property>
</bean>
</beans>

pojo类(与数据库映射那个类)

1
2
3
4
5
6
public class User {
private int id;
private String name;
private String password;
省略set与get方法。。
}

映射文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.zwl.pojo">
<class name="User" table="user" >
<id name="id" >
<generator class="increment"></generator>
</id>
<property name="name">
</property>
<property name="password">
</property>
</class>
</hibernate-mapping>

接口

接下来就是接口编写

dao层

1
2
3
4
public interface returnuserdao {
//通过id返回User
public User returnuserbyid(int id);
}

service层

1
2
3
public interface returnuserservice {
public User returnuser(int id);
}

分别得实现类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class returnuserdaoimpl extends HibernateDaoSupport implements returnuserdao {
@Override
public User returnuserbyid(int id) {
List list=this.getHibernateTemplate().find(" from User user where user.id = '" + id + "'");
if(list.size()==0){
return null;
}else{
return (User)list.get(0);
} }}
public class returnuserserviceimpl implements returnuserservice{
private returnuserdao userdao;
public returnuserdao getUserdao() {
return userdao;
}
public void setUserdao(returnuserdao userdao) {
this.userdao = userdao;
}
@Override
public User returnuser(int id) {
// TODO Auto-generated method stub
return userdao.returnuserbyid(id);
}}

这里只有两个页面,一个只有二维码,另一个是扫描后跳转的页面并且可以从数据库中取出相关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<figure>
<figcaption>图书1扫码:</figcaption>
<img src="img/dl.gif">你本地生成的二维码图片
</figure>
```
接下来是通过ajax从后台异步加载数据,当然是在你扫码后,直接将数据显示在表单中
``` stylus
<script type="text/javascript">
$(function(){
/* 通过ajax异步提交表单 */
$.ajax({
/* 提交路径 */
url : '${pageContext.request.contextPath}/userreturn!userreturn.action',
data:params,
type:"POST",
dataType:"json",
/* 提交成功后,并得到后台返回的数据 */
success : function(r) {
/* 解析后台json格式,并得到对象 */
$("#id").val(r.id);
$("#name").val(r.name);
$("#password").val(r.password);
}
});
});
</script>
<body>
<form action="" method="post">
id :&nbsp;<input id="id" name="id" type="text"/><br/>
name :&nbsp;<input id="name" name="name" type="text"/><br/>
password :&nbsp;<input id="password" name="password" type="text"/><br/>
</form>
</body>

Action类

接下来就是action的编写
首先是 QRCodeAction

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class QRCodeAction extends ActionSupport {
private static final long serialVersionUID = 1L;
// 封装上传文件域的属性
private File image;
// 封装上传文件类型的属性
private String imageContentType;
// 封装上传文件名的属性
private String imageFileName;
private String message;
private String content;
此处省略属性的set与get方法。。
/**
* 生成二维码
* @return String
*
*/
public String encoderQRCode(){
String realpath = ServletActionContext.getServletContext().getRealPath("/file");
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String imgName = sdf.format(new Date()) + ".png";
String imgPath= realpath+"/"+imgName;
QRCode.encoderQRCode(content, imgPath, "png");
message = imgName;
return Action.SUCCESS;
}
/**
* 获取二维码
* @return String
*
*/
public String decoderQRCode() {
try {
String realpath = ServletActionContext.getServletContext().getRealPath("/img");
File savefile = new File(new File(realpath), imageFileName);
if (!savefile.getParentFile().exists())
savefile.getParentFile().mkdirs();
FileUtils.copyFile(image, savefile);
message = QRCode.decoderQRCode(realpath+"/"+imageFileName);
} catch (IOException e) {
e.printStackTrace();
}
return Action.SUCCESS;
}

然后是我们需要的userreturnaction(主要后台信息通过json格式传给前台)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class userreturn {
private returnuserservice returnuser; //通过用户id查询用户信息
private String img; //接受二维码图片的名字
省略set与get方法。。
//解析二维码,入库查询,并返回用户信息
public void userreturn() throws Exception {
HttpServletResponse response=ServletActionContext.getResponse();
HttpServletRequest request=ServletActionContext.getRequest();
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8"); //返回json数据
response.setHeader("Cache-Control", "no-cache"); //不要缓存
response.setHeader("Pragma", "no-cache");
PrintWriter out = response.getWriter();
System.out.println("被扫描的二维码图片的名字:"+img);
QRCode qrcode=new QRCode();
String path=qrcode.decoderQRCode("E:/newday/librarytest/WebRoot/img/"+img);//二维码图片地址
System.out.println("二维码解析的内容:"+path);
int id=Integer.parseInt(path.substring(path.length()-1));
System.out.println("用户的id号:"+id);
User user=returnuser.returnuser(id);
System.out.println("用户的姓名:"+user.getName());
System.out.println("用户的密码:"+user.getPassword());
JsonObject json=new JsonObject();
json.addProperty("id", id);
json.addProperty("name", user.getName());
json.addProperty("password", user.getPassword());
response.getWriter().write(json.toString());
}
}

注意在页面中需要jquery-1.8.3.js包,同时此处json格式转换用的是gson.jar包
最后就是struts.xml配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constant name="struts.i18n.encoding" value="utf-8"/>
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="struts.devMode" value="false" />
<constant name="struts.i18n.encoding" value="UTF-8"/>
<constant name="struts.multipart.maxSize" value="10701096"/><!-- 上传文件最大值 -->
<constant name="struts.multipart.saveDir" value="/tmp"/><!-- 上传文件设置属性 -->
<constant name="struts.custom.i18n.resources" value="global" />
<constant name="struts.action.extension" value="action"></constant>
<package namespace="/" name="struct2" extends="struts-default">
<action name="userreturn" class="userreturn" method="userreturn">
</action>
</package>
<package name="QRCode" extends="json-default">
<action name="qRCodeAction_*" class="com.zwl.action.QRCodeAction" method="{1}" >
<result type="json">
<param name="root">message</param>
</result>
</action>
</package>
</struts>

最后打开含有二维码那个页面,然后扫一扫就可以跳转到含数据的界面,当然笔者之前遇到了几个问题,首先是图片地址在action中要正确,不然出现null,其次这是只能一个二维码并且含参数id的,只能有一个action,当然可以优化。。。

热评文章