大二学生党一枚,这两个月一直在写一个用structs2框架实现微信二次开发的web程序,前几天将这个程序写完之后,在此沉淀一下。有不准确的地方希望大家指出。
在介绍之前先发送传送门:
由于所有的学习资源来自于google,所以就把干货也链过来了,希望以下各位博主支持。
gitlab代码传送http://mukever.online/root/kaowu
javaweb学习记录http://www.cnblogs.com/xdp-gacl/p/3760336.html
structs2拦截器http://blog.csdn.net/kiss_vicente/article/details/7597700
柳峰的微信开发教程http://blog.csdn.net/lyq8479/article/details/8937622
微信开发文档http://mp.weixin.qq.com/wiki/home/
git使用(多人协作)http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/
系统实现的功能是:
微信用户通过关注微信公众号,可以实现跟系统web通信,(学院管理员通过审核通过后才能使用相关的功能,否则会友情提示)。
微信开发步骤:
1.获得接口权限
在调用接口前,微信会通过get方式向你的服务器发送几个字符串参数,可以根据开发文档提示,得到这几个参数,
(如果加密之后还需要对数据解密得到)然后向微信服务器原样返回echostr参数内容,就能完成接口的调用。
2.保存accesstoken
每次调用接口时需要验证accesstoken是否有效,我的做法是将其存入数据库,下次需要时直接将其拿出,并比对时间戳,如果失效则重新获取accesstoken。
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import com.db.kaowu.sau.www.DBUnit;
import com.pojo.wechat.kaowu.sau.www.AccessToken;
/**
* 保持token长期有效
*
*/
public class GetExistAccessToken implements AppId {
// 将AccessToken写进数据库
public static AccessToken getToken() {
Connection connection = null;
AccessToken token = new AccessToken();
connection = DBUnit.getConn();
String query_sql = "select * from db_accesstoken";
String delete_sql = "delete from db_accesstoken";
String insert_sql = "";
Date nowdate = new Date();
String dateformdb = "";
try {
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query_sql);
// 当数据库中有数据时
if (resultSet.next()) {
dateformdb = resultSet.getString(3);
// 判断数据库中的数据是否有效 为了保存数据的有效性 将token的有效期缩短50秒
if (nowdate.getTime() - Long.parseLong(dateformdb) <= 7150000) {
// System.out.println("数据库");
token.setToken(resultSet.getString(2));
token.setExpiresIn(7200);
} else {
// 数据库中的token失效了
// 调用接口获取access_token
// System.out.println("获取");
AccessToken at = WeixinUtil.getAccessToken(appId, appSecret);
// 删除原有token
statement.executeUpdate(delete_sql);
// 拼接inset_sql
insert_sql = "insert into db_accesstoken (token, date) values('" + at.getToken() + "' ,'"
+ nowdate.getTime() + "')";
// 跟新token
statement.executeUpdate(insert_sql);
// 返回的token
token = at;
}
} else {
// 数据库没有数据时肯定直接从微信服务器获取 然后存入数据库
// 调用接口获取access_token
AccessToken at = WeixinUtil.getAccessToken(appId, appSecret);
// 拼接inset_sql
insert_sql = "insert into db_accesstoken (token, date) values('" + at.getToken() + "' ,'"
+ nowdate.getTime() + "')";
// 跟新token
// System.out.println("获取");
statement.executeUpdate(insert_sql);
// 返回的token
token = at;
}
// 关闭数据库连接
closeConnection(connection);
} catch (SQLException e) {
e.printStackTrace();
if (connection != null) {
try {
connection.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
}
return token;
}
// 关闭数据库连接
public static void closeConnection(Connection connection) throws SQLException {
connection.close();
}
}
这样能保证每次就不用从微信服务器那获取accesstoken,
3.微信接口的调用
在柳峰的博客中写的已经很详细了,他把所需要解析的各种信息基类都做了封装,我们完全可以利用嘛(没必要造重复的轮子)
4.微信开发中需要注意的问题:
1)接口权限问题,由于普通公众号没有高级权限,可以通过使用微信测试账号开发。
2)自己的服务器跟微信服务器是通过json数据传输。
3)在拦截请求时,需要放过处理微信服务器发送的请求。
4)手机端跟微信交互的时候 ,后台报错时,手机端的微信会提示无法响应。(正常情况下,服务器都会在5秒处理完请求)
5)不管是php还是java,开发的思路都是一样的。
后台开发步骤:
1.数据库设计:
2.前台页面与后台交互
前台页面通过js+jquery+ajax跟后台通过传递json数据做交互
3.action配置
<struts>
<package name="struts" namespace="/" extends="struts-default,json-default">
<interceptors>
<interceptor name="permission" class="com.filter.kaowu.sau.www.SessionIterceptor" />
<interceptor-stack name="permissionStack">
<interceptor-ref name="defaultStack" />
<interceptor-ref name="permission" />
interceptor-stack>
interceptors>
<default-interceptor-ref name="permissionStack" />
<global-results>
<result name="nologin" type="redirect">/login.htmlresult>
global-results>
<action name="Login" class="com.action.kaowu.sau.www.Login">
<result name = "success" type="json">
<param name="root">resultparam>
result>
<result name="input">/login.htmlresult>
action>
<action name="Sign_*" class="com.action.kaowu.sau.www.Sign" method="{1}">
<result name="success">/idnex.htmlresult>
<result type="json">
<param name="root">resultparam>
result>
action>
<action name="WeChat_*" class="com.action.kaowu.sau.www.WeChat" method="{1}">
action>
<action name="Register" class="com.action.kaowu.sau.www.Register">
<result name = "success" type="json">
<param name="root">resultparam>
result>
action>
<action name="AuditUser" class="com.action.kaowu.sau.www.AuditUser">
<result name = "success" type="json">
<param name="root">resultparam>
result>
action>
<action name="Audit" class="com.action.kaowu.sau.www.Audit">
<result name = "success" type="json">
<param name="root">resultparam>
result>
action>
<action name="UserInfo" class="com.action.kaowu.sau.www.UserInfo">
<result name = "success" type="json">
<param name="root">resultparam>
result>
action>
<action name="Grade_*" class="com.action.kaowu.sau.www.Grade" method="{1}">
<result name="add" type="json">
<param name="root">resultparam>
result>
<result name="delete" type="json">
<param name="root">resultparam>
result>
<result name="getList" type="json">
<param name="root">resultparam>
result>
action>
<action name="ClassRoom_*" class="com.action.kaowu.sau.www.ClassRoom" method="{1}">
<result name="add" type="json">
<param name="root">resultparam>
result>
<result name="delete" type="json">
<param name="root">resultparam>
result>
<result name="getList" type="json">
<param name="root">resultparam>
result>
<result name="update" type="json">
<param name="root">resultparam>
result>
action>
<action name="NotUseRoom" class="com.action.kaowu.sau.www.NotUseRoom">
<result name="success" type="json">
<param name="root">resultparam>
result>
action>
<action name="CreateNewTest" class="com.action.kaowu.sau.www.CreateNewTest">
<result name="success" type="json">
<param name="root">resultparam>
result>
action>
<action name="NotUseTher" class="com.action.kaowu.sau.www.NotUseTher">
<result name="success" type="json">
<param name="root">resultparam>
result>
action>
<action name="AffirmTest" class="com.action.kaowu.sau.www.AffirmTest">
<result name="success" type="json">
<param name="root">resultparam>
result>
action>
<action name="TestList_*" class="com.action.kaowu.sau.www.TestList" method="{1}">
<result name = "getlist" type="json">
<param name="root">resultparam>
result>
<result name = "delete" type="json">
<param name="root">statusparam>
result>
action>
<action name="Admin_*" class="com.action.kaowu.sau.www.Admin" method="{1}">
<result name="updata" type="json">
<param name="root">resultparam>
result>
<result name="add" type="json">
<param name="root">resultparam>
result>
<result name="delete" type="json">
<param name="root">resultparam>
result>
<result name="list" type="json">
<param name="root">resultparam>
result>
action>
<action name="UserInfoupdata" class="com.action.kaowu.sau.www.UserInfoupdata">
<result name="updata" type="json">
<param name="root">resultparam>
result>
action>
<action name="UserTest" class="com.action.kaowu.sau.www.UserTest">
<result name="success" type="json">
<param name="root">resultparam>
result>
action>
<action name="Quit" class="com.action.kaowu.sau.www.Quit">
<result name="success">/login.html
result>
action>
package>
4.jdbc连接数据库
1)将用户名和密码写在web.xml文件里面
package com.db.kaowu.sau.www;
import java.sql.*;
import javax.servlet.ServletContext;
import org.apache.struts2.ServletActionContext;
/*
*
* 数据库连接对象
*/
public class DBUnit {
// 返回数据库连接对象
public static Connection getConn() {
ServletContext context = ServletActionContext.getServletContext();
// 连接数据库
String url = context.getInitParameter("url");
String username = context.getInitParameter("username");
String psd = context.getInitParameter("password");
String jdbcName = context.getInitParameter("driver");
Connection conn = null;
try {
Class.forName(jdbcName);
// System.out.println("驱动加载成功!");
} catch (Exception e) {
}
try {
// 本地连接
// conn=DriverManager.getConnection(url);
// 服务器连接
conn = DriverManager.getConnection(url, username, psd);
} catch (SQLException ex) {
}
return conn;
}
}
5.web.xml文件配置
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<filter>
<filter-name>struts2filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilterfilter-class>
filter>
<filter-mapping>
<filter-name>struts2filter-name>
<url-pattern>*.actionurl-pattern>
filter-mapping>
<welcome-file-list>
<welcome-file>/login.htmlwelcome-file>
welcome-file-list>
<session-config>
<session-timeout>30session-timeout>
session-config>
<context-param>
<param-name>appIdparam-name>
<param-value>wxd667c09a8220e9eaparam-value>
context-param>
<context-param>
<param-name>appSecretparam-name>
<param-value>d3db5e22bfc9f761e4f70b3fe2bbd8b4param-value>
context-param>
<context-param>
<param-name>demarcationparam-name>
<param-value>100param-value>
context-param>
<error-page>
<error-code>404error-code>
<location>/404.htmllocation>
error-page>
<context-param>
<param-name>driverparam-name>
<param-value>com.mysql.jdbc.Driverparam-value>
context-param>
<context-param>
<param-name>urlparam-name>
<param-value>jdbc:mysql://localhost:3306/kaowuparam-value>
context-param>
<context-param>
<param-name>usernameparam-name>
<param-value>rootparam-value>
context-param>
<context-param>
<param-name>passwordparam-name>
<param-value>param-value>
context-param>
web-app>
6.业务逻辑部分
1)审核
2.添加管理员
3.学院教务人员安排考试后台
4.新建考试完成后会向参加该门考试的教师托推送消息
package com.action.kaowu.sau.www;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import com.CoreServer.wechat.kaowu.sau.www.HttpRequest;
import com.bean.kaowu.sau.www.SpecificrecordBean;
import com.bean.kaowu.sau.www.TestBean;
import com.dao.kaowu.sau.www.OpenidDAO;
import com.dao.kaowu.sau.www.RegisterDAO;
import com.dao.kaowu.sau.www.SpecificrecordDAO;
import com.dao.kaowu.sau.www.TestDAO;
import com.opensymphony.xwork2.ActionSupport;
import com.units.wechat.kaowu.sau.edu.www.GetExistAccessToken;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
public class AffirmTest extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = 1L;
private String testlist;
private String testrecord;
private String result;
public String getTestlist() {
return testlist;
}
public void setTestlist(String testlist) {
this.testlist = testlist;
}
public String getTestrecord() {
return testrecord;
}
public void setTestrecord(String testrecord) {
this.testrecord = testrecord;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public String execute() {
synchronized (this) {
// 获得到此次考试的时间+科目
HttpSession session = ServletActionContext.getRequest().getSession();
String Project = (String) session.getAttribute("Project");
String Starttime = (String) session.getAttribute("Starttime");
String Endtime = (String) session.getAttribute("Endtime");
String College = (String) session.getAttribute("College_num");
JSONObject jsonObject = JSONObject.fromObject(testlist);
String testrecord = jsonObject.getString("testrecord");
String arr_temp = jsonObject.getString("testlist");
JSONArray array = JSONArray.fromObject(arr_temp);
// 临时保存teacherid数据
List ids = new ArrayList<>();
List list = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JSONObject o = array.getJSONObject(i);
SpecificrecordBean js = new SpecificrecordBean();
js.setClassid(o.getString("Classid"));
js.setGradeid_1(o.getString("Gradeid_1"));
js.setGradeid_2(o.getString("Gradeid_2"));
js.setTeacherid_1(o.getString("Teacherid_1"));
RegisterDAO.count(o.getString("Teacherid_1"));
js.setTeacherid_2(o.getString("Teacherid_2"));
RegisterDAO.count(o.getString("Teacherid_2"));
js.setTestrecord(testrecord);
list.add(js);
// 向微信发送数据
ids.add(o.getString("Teacherid_1"));
ids.add(o.getString("Teacherid_2"));
}
SpecificrecordBean[] temp = new SpecificrecordBean[array.size()];
for (int i = 0; i < temp.length; i++) {
temp[i] = list.get(i);
}
TestBean testBean = new TestBean();
testBean.setProject(Project);
testBean.setStarttime(Starttime);
testBean.setEndtime(Endtime);
testBean.setTestid(testrecord);
testBean.setCollege(Integer.parseInt(College));
TestDAO.add(testBean);
SpecificrecordDAO.add(temp);
JSONObject jsonObject2 = new JSONObject();
jsonObject2.put("list", temp);
// 前端的数据
result = jsonObject2.toString();
// 调用微信的高级接口推送消息
JSONArray Openid = new JSONArray();
// 构建openid数据库查找sql
StringBuilder builder = new StringBuilder();
if (ids.size() > 0) {
builder.append("where Therid in (");
// 构造查询字符串
int k = ids.size();
for (int i = 0; i < k; i++) {
if (i == k - 1) {
builder.append(" '" + ids.get(i) + "')");
} else {
builder.append(" '" + ids.get(i) + "',");
}
}
}
List openids = OpenidDAO.getOpenid(builder.toString());
for (String s : openids) {
Openid.add(s);
}
JSONObject ToAll = new JSONObject();
JSONObject content = new JSONObject();
content.put("content", "您近期有新的监考信息\n请点击考务助手\n我的监考查询");
ToAll.put("touser", Openid);
ToAll.put("msgtype", "text");
ToAll.put("text", content);
String url = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=ACCESS_TOKEN";
String access_token = GetExistAccessToken.getToken().getToken();
url = url.replace("ACCESS_TOKEN", access_token);
HttpRequest.httpsRequest(url, "POST", ToAll.toString());
return SUCCESS;
}
}
}