Bläddra i källkod

IC卡程序初始化

chenw 7 år sedan
förälder
incheckning
1bcdfb0145
13 ändrade filer med 776 tillägg och 12 borttagningar
  1. 10 0
      applications/device/device-client/pom.xml
  2. 2 7
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/DeviceClientApplication.java
  3. 91 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/config/RestTemplateConfig.java
  4. 132 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/AccTransDetail.java
  5. 174 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/MessageInfo.java
  6. 49 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/Transaction.java
  7. 1 1
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/repository/SchoolRepository.java
  8. 118 4
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/service/IcCardService.java
  9. 51 0
      applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/utils/HmacUtils.java
  10. 3 0
      applications/device/device-client/src/main/resources/application.yml
  11. 40 0
      applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/Hex.java
  12. 96 0
      applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/HmacEncoder.java
  13. 9 0
      applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/HmacSHA256Encoder.java

+ 10 - 0
applications/device/device-client/pom.xml

@@ -37,6 +37,16 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-jdbc</artifactId>
         </dependency>
+        <!-- JSON -->
+        <dependency>
+          <groupId>com.alibaba</groupId>
+          <artifactId>fastjson</artifactId>
+        </dependency>
+        <!-- httpClient -->
+        <dependency>
+          <groupId>org.apache.httpcomponents</groupId>
+          <artifactId>httpclient</artifactId>
+        </dependency>
     </dependencies>
 
 </project>

+ 2 - 7
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/DeviceClientApplication.java

@@ -4,9 +4,8 @@ import com.usoftchina.smartschool.device.client.config.DeviceServerProperties;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.annotation.Bean;
 import org.springframework.scheduling.annotation.EnableAsync;
-import org.springframework.web.client.RestTemplate;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 /**
  * @author yingp
@@ -15,13 +14,9 @@ import org.springframework.web.client.RestTemplate;
 @SpringBootApplication
 @EnableAsync
 @EnableConfigurationProperties(DeviceServerProperties.class)
+@EnableScheduling
 public class DeviceClientApplication {
     public static void main(String[] args) {
         SpringApplication.run(DeviceClientApplication.class, args);
     }
-
-    @Bean
-    public RestTemplate restTemplate() {
-        return new RestTemplate();
-    }
 }

+ 91 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/config/RestTemplateConfig.java

@@ -0,0 +1,91 @@
+package com.usoftchina.smartschool.device.client.config;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.TrustStrategy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import java.nio.charset.Charset;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.List;
+
+/**
+ * @Author chenwei
+ * @Date 2019/03/07
+ */
+@Configuration
+public class RestTemplateConfig {
+
+    private static final Logger logger = LoggerFactory.getLogger(RestTemplateConfig.class);
+
+    @Bean
+    public RestTemplate restTemplate(){
+        RestTemplate restTemplate = new RestTemplate();
+        List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
+        converterList.add(0, responseBodyConverter());
+        restTemplate.setRequestFactory(httpRequestFactory());
+        return restTemplate;
+    }
+
+    @Bean
+    public HttpMessageConverter<String> responseBodyConverter() {
+        StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
+        return converter;
+    }
+
+    @Bean
+    public HttpComponentsClientHttpRequestFactory httpRequestFactory(){
+        try {
+            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
+            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
+                public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+                    return true;
+                }
+            }).build();
+            httpClientBuilder.setSSLContext(sslContext);
+            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
+            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
+            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
+                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
+                    .register("https", sslConnectionSocketFactory).build();// 注册http和https请求
+            // 开始设置连接池
+            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+            poolingHttpClientConnectionManager.setMaxTotal(500); // 最大连接数500
+            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); // 同路由并发数100
+            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
+            httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重试次数
+            HttpClient httpClient = httpClientBuilder.build();
+            HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient连接配置
+            clientHttpRequestFactory.setConnectTimeout(20000);              // 连接超时
+            clientHttpRequestFactory.setReadTimeout(30000);                 // 数据读取超时时间
+            clientHttpRequestFactory.setConnectionRequestTimeout(20000);    // 连接不够用的等待时间
+            return clientHttpRequestFactory;
+        }catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e){
+            logger.info("初始化HTTP连接池出错, message={}", e);
+        }
+        return null;
+    }
+
+}

+ 132 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/AccTransDetail.java

@@ -0,0 +1,132 @@
+package com.usoftchina.smartschool.device.client.po;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * @Description 交易记录
+ * @Author chenwei
+ * @Date 2019/03/07
+ */
+public class AccTransDetail implements Serializable {
+    /**
+     * 交易ID
+     */
+    private String guid;
+    /**
+     * 用户ID
+     */
+    private String empSysID;
+    /**
+     * 学号
+     */
+    private String empNo;
+    /**
+     * 姓名
+     */
+    private String empName;
+    /**
+     * 账户
+     */
+    private String accNo;
+    /**
+     * 交易类型
+     */
+    private String accTransType;
+    /**
+     * 交易日期
+     */
+    private Date accTransDay;
+    /**
+     * 收入
+     */
+    private Double iMoneyValue;
+    /**
+     * 支出
+     */
+    private Double oMoneyValue;
+    /**
+     * 余额
+     */
+    private Double cardMoneyValue;
+
+    public String getGuid() {
+        return guid;
+    }
+
+    public void setGuid(String guid) {
+        this.guid = guid;
+    }
+
+    public String getEmpSysID() {
+        return empSysID;
+    }
+
+    public void setEmpSysID(String empSysID) {
+        this.empSysID = empSysID;
+    }
+
+    public String getEmpNo() {
+        return empNo;
+    }
+
+    public void setEmpNo(String empNo) {
+        this.empNo = empNo;
+    }
+
+    public String getEmpName() {
+        return empName;
+    }
+
+    public void setEmpName(String empName) {
+        this.empName = empName;
+    }
+
+    public String getAccNo() {
+        return accNo;
+    }
+
+    public void setAccNo(String accNo) {
+        this.accNo = accNo;
+    }
+
+    public String getAccTransType() {
+        return accTransType;
+    }
+
+    public void setAccTransType(String accTransType) {
+        this.accTransType = accTransType;
+    }
+
+    public Date getAccTransDay() {
+        return accTransDay;
+    }
+
+    public void setAccTransDay(Date accTransDay) {
+        this.accTransDay = accTransDay;
+    }
+
+    public Double getiMoneyValue() {
+        return iMoneyValue;
+    }
+
+    public void setiMoneyValue(Double iMoneyValue) {
+        this.iMoneyValue = iMoneyValue;
+    }
+
+    public Double getoMoneyValue() {
+        return oMoneyValue;
+    }
+
+    public void setoMoneyValue(Double oMoneyValue) {
+        this.oMoneyValue = oMoneyValue;
+    }
+
+    public Double getCardMoneyValue() {
+        return cardMoneyValue;
+    }
+
+    public void setCardMoneyValue(Double cardMoneyValue) {
+        this.cardMoneyValue = cardMoneyValue;
+    }
+}

+ 174 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/MessageInfo.java

@@ -0,0 +1,174 @@
+package com.usoftchina.smartschool.device.client.po;
+
+import java.io.Serializable;
+
+/**
+ * @Author chenwei
+ * @Date 2019/03/08
+ */
+public class MessageInfo implements Serializable {
+
+    private String msgId;
+    /**
+     * 公众号id
+     */
+    private String appId;
+
+    /**
+     * 公众号密钥
+     */
+    private String secret;
+
+    /*
+     * 推送人微信标识
+     */
+    private String touser;
+
+    /**
+     * 微信模板id
+     */
+    private String templateId;
+
+    private String title;
+
+    private String keyword1;
+
+    private String keyword2;
+
+    private String keyword3;
+
+    private String keyword4;
+
+    private String keyword5;
+
+    private String keyword6;
+
+    private int userType;
+
+    private String remark;
+
+    private String url;
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
+
+    public String getTouser() {
+        return touser;
+    }
+
+    public void setTouser(String touser) {
+        this.touser = touser;
+    }
+
+    public String getTemplateId() {
+        return templateId;
+    }
+
+    public void setTemplateId(String templateId) {
+        this.templateId = templateId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getKeyword1() {
+        return keyword1;
+    }
+
+    public void setKeyword1(String keyword1) {
+        this.keyword1 = keyword1;
+    }
+
+    public String getKeyword2() {
+        return keyword2;
+    }
+
+    public void setKeyword2(String keyword2) {
+        this.keyword2 = keyword2;
+    }
+
+    public String getKeyword3() {
+        return keyword3;
+    }
+
+    public void setKeyword3(String keyword3) {
+        this.keyword3 = keyword3;
+    }
+
+    public String getKeyword4() {
+        return keyword4;
+    }
+
+    public void setKeyword4(String keyword4) {
+        this.keyword4 = keyword4;
+    }
+
+    public String getKeyword6() {
+        return keyword6;
+    }
+
+    public void setKeyword6(String keyword6) {
+        this.keyword6 = keyword6;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getKeyword5() {
+        return keyword5;
+    }
+
+    public void setKeyword5(String keyword5) {
+        this.keyword5 = keyword5;
+    }
+
+    public int getUserType() {
+        return userType;
+    }
+
+    public void setUserType(int userType) {
+        this.userType = userType;
+    }
+
+    public String getMsgId() {
+        return msgId;
+    }
+
+    public void setMsgId(String msgId) {
+        this.msgId = msgId;
+    }
+
+
+
+}

+ 49 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/po/Transaction.java

@@ -0,0 +1,49 @@
+package com.usoftchina.smartschool.device.client.po;
+
+public enum Transaction {
+
+    AUTO_RECHARGE("自动充值", "10"),
+    HAND_RECHARGE("手动充值", "11"),
+    TRANSFER_RECHARGE("转账充值", "12"),
+    SUPPLEMENT__RECHARGE("补账充值", "13"),
+    TRAPS_RECHARGE("圈存充值", "14"),
+
+    CONSUMPTION_PAY("消费支出", "20"),
+    REFUND("退款", "21"),
+    CLOSE_ACCOUNT("销户", "22"),
+    TRANSFER_PAY("转账支出", "23"),
+    SUPPLEMENT_PAY("补账支出", "24");
+
+    private String name;
+    private String code;
+
+    Transaction(String name, String code) {
+        this.name = name;
+        this.code = code;
+    }
+
+    public static String getName(String code){
+        for (Transaction transaction : Transaction.values()) {
+            if (transaction.getCode().equals(code)) {
+                return transaction.name;
+            }
+        }
+        return null;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}

+ 1 - 1
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/repository/SchoolRepository.java

@@ -19,7 +19,7 @@ public class SchoolRepository{
 
     public School find() {
         try {
-            return jdbcTemplate.queryForObject("select * from iccard",
+            return jdbcTemplate.queryForObject("select * from school",
                     new BeanPropertyRowMapper<>(School.class));
         } catch (EmptyResultDataAccessException e) {
             return null;

+ 118 - 4
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/service/IcCardService.java

@@ -1,13 +1,30 @@
 package com.usoftchina.smartschool.device.client.service;
 
+import com.alibaba.fastjson.JSON;
+import com.usoftchina.smartschool.device.base.Result;
 import com.usoftchina.smartschool.device.client.jdbc.DynamicDataSourceContextHolder;
 import com.usoftchina.smartschool.device.client.jdbc.DynamicDataSourceRegister;
-import com.usoftchina.smartschool.device.client.po.IcCard;
+import com.usoftchina.smartschool.device.client.po.*;
 import com.usoftchina.smartschool.device.client.repository.IcCardRepository;
+import com.usoftchina.smartschool.device.client.utils.HmacUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.*;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+import java.net.URI;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * @author yingp
@@ -19,9 +36,32 @@ public class IcCardService {
     @Autowired
     private IcCardRepository icCardRepository;
 
+    @Autowired
+    private SchoolService schoolService;
+
     @Autowired
     private DynamicDataSourceRegister dynamicDataSourceRegister;
 
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    @Value("${device.icCard.icCardUrl}")
+    private String targetURL;
+
+    //SQL语句
+    private static final String insertSql = "INSERT INTO XF_AccTransDetail_push(GUID,AccNo,AccTransDay,AccTransType,IMoneyValue,OMoneyValue,CardUseNum,CardMoneyValue,DevID,DevOwner,OprtNo,Remark,XFDataSysID,XFPosMoneyByCredit,SendStatus,CreateTime) "
+            + " SELECT SOURCE.GUID,SOURCE.AccNo,SOURCE.AccTransDay,SOURCE.AccTransType,SOURCE.IMoneyValue,SOURCE.OMoneyValue,SOURCE.CardUseNum,SOURCE.CardMoneyValue,SOURCE.DevID,SOURCE.DevOwner,SOURCE.OprtNo,SOURCE.Remark,SOURCE.XFDataSysID,SOURCE.XFPosMoneyByCredit,'待上传',GETDATE() "
+            + " FROM XF_AccTransDetail SOURCE WHERE NOT EXISTS (SELECT 1 FROM XF_AccTransDetail_push TARGET WHERE SOURCE.GUID = TARGET.GUID)";
+
+    private static final String getDataSql = "select top 100 XF_AccTransDetail_push.GUID,RS_EMP.EmpSysID,RS_EMP.EmpNo,RS_EMP.EmpName,XF_AccHead.AccNo, XF_AccTransDetail_push.AccTransType,XF_AccTransDetail_push.AccTransDay,XF_AccTransDetail_push.IMoneyValue,XF_AccTransDetail_push.OMoneyValue,XF_AccTransDetail_push.CardMoneyValue "
+            + "from XF_AccTransDetail_push left join XF_AccHead on XF_AccTransDetail_push.AccNo=XF_AccHead.AccNo left join Tx_EmpCard on Tx_EmpCard.CardID=XF_AccHead.CardID "
+            + "left join RS_EMP ON RS_EMP.EmpSysID=XF_AccHead.EmpSysID where XF_AccTransDetail_push.SendStatus=? order by AccTransDay desc";
+
+    private static final String updateSql = "update XF_AccTransDetail_push set SendStatus = ? where GUID in (?)";
+
     public IcCard find() {
         return icCardRepository.find();
     }
@@ -38,16 +78,90 @@ public class IcCardService {
         dynamicDataSourceRegister.createDataSource(card);
     }
 
-    @Scheduled(cron = "", initialDelay = 5000)
+    @Scheduled(fixedRate = 1000 * 60, initialDelay = 5000)
     public void dataTask() {
         IcCard card = find();
-        if (null != card && dynamicDataSourceRegister.contains(card)) {
+        School school = schoolService.find();
+        if (null != card && dynamicDataSourceRegister.contains(card) && null != school) {
             DynamicDataSourceContextHolder.set(card);
             try {
-                // TODO
+                doTask();
             } finally {
                 DynamicDataSourceContextHolder.clear();
             }
         }
     }
+
+    private void doTask(){
+        //1.准备本次需要传输的数据->转移至中间表
+        jdbcTemplate.execute(insertSql);
+        //2.获取本次传输的数据
+        List<AccTransDetail> resultList = jdbcTemplate.query(getDataSql, new BeanPropertyRowMapper<>(AccTransDetail.class), "待上传");
+        List<MessageInfo> messageInfoList = new ArrayList<MessageInfo>();
+        StringBuilder sb = new StringBuilder();
+        resultList.forEach(accTransDetail -> {
+            sb.append(accTransDetail.getGuid() + ",");
+            String oldType = accTransDetail.getAccTransType();
+            accTransDetail.setAccTransType(Transaction.getName(accTransDetail.getAccTransType()));
+            //构造messageInfo对象
+            MessageInfo messageInfo = new MessageInfo();
+            messageInfo.setMsgId(accTransDetail.getGuid());
+            messageInfo.setTouser(accTransDetail.getEmpNo());
+            //messageInfo.setTouser("o8lZ9uNXXY7VSfNM6be-7VZNkcOw");
+            messageInfo.setTouser(accTransDetail.getEmpName());
+            messageInfo.setUserType(2);
+            messageInfo.setTemplateId("FhtdzLdpzLLp4eJGtgvH4SUfIpSIF0kWwIpsWsSBp6c");
+            String accNo = accTransDetail.getAccNo();
+            String cardNo = StringUtils.isEmpty(accNo) ? null : accNo.substring(accTransDetail.getAccNo().length() - 4);
+            String header = "您好,您的小孩" + accTransDetail.getEmpName() + "在校的校园卡(卡号:*** " + cardNo + ")发生如下交易";
+            messageInfo.setTitle(header);
+            messageInfo.setKeyword1(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(accTransDetail.getAccTransDay()));
+            if (Integer.parseInt(oldType) > 15) {
+                messageInfo.setKeyword2(String.format("%.2f", accTransDetail.getoMoneyValue()));
+            }else {
+                messageInfo.setKeyword2(String.format("%.2f", accTransDetail.getiMoneyValue()));
+            }
+            messageInfo.setKeyword3(accTransDetail.getAccTransType());
+            messageInfo.setKeyword4(String.format("%.2f", accTransDetail.getCardMoneyValue()));
+            messageInfo.setRemark("感谢您使用");
+            messageInfoList.add(messageInfo);
+        });
+        //3.传输
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        MultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
+        requestEntity.add("data", JSON.toJSONString(messageInfoList));
+        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(requestEntity, headers);
+        //禁止对该url进行encode操作
+        DefaultUriBuilderFactory defaultUriBuilderFactory = new DefaultUriBuilderFactory();
+        defaultUriBuilderFactory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
+        restTemplate.setUriTemplateHandler(defaultUriBuilderFactory);
+        ResponseEntity<String> responseEntity = restTemplate.postForEntity(getURI(targetURL, "/send"), httpEntity, String.class);
+        //4.完成后,将传输的成功的数据状态更新为"已上传"
+        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
+            Result result = JSON.parseObject(responseEntity.getBody(), Result.class);
+            if (result.isSuccess()) {
+                String ids = "'" + sb.substring(0, sb.length() - 1).replaceAll(",", "','") + "'";
+                jdbcTemplate.update(updateSql, "已上传", ids);
+            }
+        }
+    }
+
+    private String getURI(String url, String subIndexOf, Object... vars){
+        StringBuilder accessUrl = new StringBuilder(url);
+        accessUrl.append(url.contains("?") ? "&" : "?");
+        // 身份ID
+        accessUrl.append("school=").append(schoolService.find().getName());
+        //时间戳
+        accessUrl.append("&_timestamp=").append(System.currentTimeMillis());
+        RestTemplate restTemplate = new RestTemplate();
+        URI uri = restTemplate.getUriTemplateHandler().expand(accessUrl.toString(), vars);
+        url = uri.toString();
+        /*if (StringUtils.isEmpty(accessSecretKey)) {
+            return url + "&_signature=" + HmacUtils.encode(url.substring(url.indexOf(subIndexOf)));
+        }else {
+            return url + "&_signature=" + HmacUtils.encode(url.substring(url.indexOf(subIndexOf)), accessSecretKey);
+        }*/
+        return url + "&_signature=" + HmacUtils.encode(url.substring(url.indexOf(subIndexOf)));
+    }
 }

+ 51 - 0
applications/device/device-client/src/main/java/com/usoftchina/smartschool/device/client/utils/HmacUtils.java

@@ -0,0 +1,51 @@
+package com.usoftchina.smartschool.device.client.utils;
+
+
+import com.usoftchina.smartschool.device.crypto.Hex;
+import com.usoftchina.smartschool.device.crypto.HmacEncoder;
+import com.usoftchina.smartschool.device.crypto.HmacSHA256Encoder;
+
+/**
+ * Hmac加密工具
+ * 
+ * @author yingp
+ *
+ */
+public class HmacUtils {
+
+	private static HmacEncoder hmacEncoder;
+
+	// 默认约定密钥
+	private final static byte[] key = { 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 117, 98, 116, 111, 98, 46, 99, 111, 109, 47,
+			101, 114, 112, 47, 115, 97, 108, 101, 47, 111, 114, 100, 101, 114, 115, 63, 115, 111, 109, 101, 116, 104, 105, 110, 103 };
+
+	static {
+		// default algorithm: HmacSHA256
+		hmacEncoder = new HmacSHA256Encoder();
+	}
+
+	/**
+	 * 
+	 * @param message
+	 *            明文
+	 * @return 16进制密文
+	 */
+	public static String encode(Object message) {
+		byte[] encodeData = hmacEncoder.encode(String.valueOf(message).getBytes(), key);
+		return new String(Hex.encode(encodeData));
+	}
+
+	/**
+	 * 
+	 * @param message
+	 *            明文
+	 * @param key
+	 *            密钥
+	 * @return 16进制密文
+	 */
+	public static String encode(Object message, String key) {
+		byte[] encodeData = hmacEncoder.encode(String.valueOf(message).getBytes(), key.getBytes());
+		return new String(Hex.encode(encodeData));
+	}
+
+}

+ 3 - 0
applications/device/device-client/src/main/resources/application.yml

@@ -5,6 +5,9 @@ device:
   server:
   # 门禁事件的服务端接口
     accessControlEvent: https://school-api.ydyhz.com/device/accesscontrol/event
+  # IC卡传输的服务端接口
+  icCard:
+    icCardUrl: https://school-api.ubtob.com/api/wechat/send/Messages
 server:
   tomcat:
     uri-encoding: UTF-8

+ 40 - 0
applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/Hex.java

@@ -0,0 +1,40 @@
+package com.usoftchina.smartschool.device.crypto;
+
+public final class Hex {
+	private static final char[] HEX = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+	public static char[] encode(byte[] bytes) {
+		int nBytes = bytes.length;
+		char[] result = new char[2 * nBytes];
+
+		int j = 0;
+		for (int i = 0; i < nBytes; ++i) {
+			result[(j++)] = HEX[((0xF0 & bytes[i]) >>> 4)];
+
+			result[(j++)] = HEX[(0xF & bytes[i])];
+		}
+
+		return result;
+	}
+
+	public static byte[] decode(CharSequence s) {
+		int nChars = s.length();
+
+		if (nChars % 2 != 0) {
+			throw new IllegalArgumentException("Hex-encoded string must have an even number of characters");
+		}
+
+		byte[] result = new byte[nChars / 2];
+
+		for (int i = 0; i < nChars; i += 2) {
+			int msb = Character.digit(s.charAt(i), 16);
+			int lsb = Character.digit(s.charAt(i + 1), 16);
+
+			if ((msb < 0) || (lsb < 0)) {
+				throw new IllegalArgumentException("Non-hex character in input: " + s);
+			}
+			result[(i / 2)] = (byte) (msb << 4 | lsb);
+		}
+		return result;
+	}
+}

+ 96 - 0
applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/HmacEncoder.java

@@ -0,0 +1,96 @@
+package com.usoftchina.smartschool.device.crypto;
+
+import javax.crypto.KeyGenerator;
+import javax.crypto.Mac;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Hash-based message authentication code,利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出
+ * 
+ * @author yingp
+ *
+ */
+public class HmacEncoder {
+
+	private final String algorithm;
+
+	public HmacEncoder(String algorithm) {
+		this.algorithm = algorithm;
+	}
+
+	/**
+	 * 根据给定密钥生成算法创建密钥
+	 * @return 密钥
+	 * @throws RuntimeException
+	 *             当 {@link NoSuchAlgorithmException} 发生时
+	 */
+	public byte[] getKey() {
+		// 初始化KeyGenerator
+		KeyGenerator keyGenerator = null;
+		try {
+			keyGenerator = KeyGenerator.getInstance(algorithm);
+		} catch (NoSuchAlgorithmException e) {
+			throw new RuntimeException(e.getMessage());
+		}
+		// 产生密钥
+		SecretKey secretKey = keyGenerator.generateKey();
+		// 获得密钥
+		return secretKey.getEncoded();
+	}
+
+	/**
+	 * 转换密钥
+	 * 
+	 * @param key
+	 *            二进制密钥
+	 * @param algorithm
+	 *            密钥算法
+	 * @return 密钥
+	 */
+	private static Key toKey(byte[] key, String algorithm) {
+		// 生成密钥
+		return new SecretKeySpec(key, algorithm);
+	}
+
+	/**
+	 * 使用指定消息摘要算法计算消息摘要
+	 * 
+	 * @param data
+	 *            做消息摘要的数据
+	 * @param key
+	 *            密钥
+	 * @return 消息摘要(长度为16的字节数组)
+	 */
+	public byte[] encode(byte[] data, Key key) {
+		Mac mac = null;
+		try {
+			mac = Mac.getInstance(algorithm);
+			mac.init(key);
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+			return new byte[0];
+		} catch (InvalidKeyException e) {
+			e.printStackTrace();
+			return new byte[0];
+		}
+		return mac.doFinal(data);
+	}
+
+	/**
+	 * 使用指定消息摘要算法计算消息摘要
+	 * 
+	 * @param data
+	 *            做消息摘要的数据
+	 * @param key
+	 *            密钥
+	 * @return 消息摘要(长度为16的字节数组)
+	 */
+	public byte[] encode(byte[] data, byte[] key) {
+		return encode(data, toKey(key, algorithm));
+	}
+
+}

+ 9 - 0
applications/device/device-core/src/main/java/com/usoftchina/smartschool/device/crypto/HmacSHA256Encoder.java

@@ -0,0 +1,9 @@
+package com.usoftchina.smartschool.device.crypto;
+
+public class HmacSHA256Encoder extends HmacEncoder {
+
+	public HmacSHA256Encoder() {
+		super("HmacSHA256");
+	}
+
+}