PayMap

PayMap是一个使用Java语言集成三方支付的小Demo,现已集成支付宝(国内、国际、移动端、PC端)、微信、银联(ACP、UPOP)、光大(网关、网页)、邮政支付,采用的技术栈为:SpringMVC+Spring+MyBatis+Shiro+RabbitMQ+Redis。

特性

支持前面提到的各种**支付

支付请求调用支持HTTP和异步MQ

控制层统一异常处理

LogBack日志记录

Redis缓存机制

Shiro安全机制

MyBatis代码自动生成

HTTP请求日志记录

RESTful APIs

说明

1、本文项目来自Martin404,自己只是临摹大佬的项目。

2、重要的是学习过程,而不是结果。但,结果同样重要,加油。gogogo。

3、框架搭建就略过了。配置文件太多。遇到的时候贴出来。也收藏起来,留着备用。

5、在IDEA中我会注重代码规范,但是这里为了节约地方,能省的就省略了。还请谅解。

6、代码提交到这里了GitHub。根据提交记录找自己想要的类库。

7、重要的在后面,一切都只只是刚刚开始(希望不要被屏蔽)!!gogogo

2、核心包~common.dao,service,web,mq.

(1)、我们先从dao开始吧,这里也可以是web。熟悉的来了,IBaseMapper 还是定义基础接口,但与中不同的是这个用泛型修饰,为什么呢?先看一张图。

图片+代码可以说明一切问题。反射+泛型。很重。要是还不懂,再用文字描述

1、泛型类,是在实例化类的时候指明泛型的具体类型;支持创建可以按类型进行参数化的类

2、泛型方法,是在调用方法的时候指明具体的类型。public List findAll() {}

3、泛型接口,JDK,Spring中大量运用泛型。

总结来说泛型可以提高Java程序的类型安全,所有的类型转换都是自动和隐式的。为优化,性能带来收益。

IBaseDao接口:

/**

* 持久层通用接口

*/

public interface IBaseDao {

void save(T entity);

void delete(T entity);

void update(T entity);

T findById(Serializable id);

List findAll();

}

BaseDaoImpl实现类:

/**

* 持久层通用实现

*/

public class BaseDaoImpl extends HibernateDaoSupport implements IBaseDao {

//代表的是某个实体的类型

private Class entityClass;

@Resource//根据类型注入spring工厂中的会话工厂对象sessionFactory

public void setMySessionFactory(SessionFactory sessionFactory){

super.setSessionFactory(sessionFactory);

}

//在父类(BaseDaoImpl)的构造方法中动态获得entityClass

public BaseDaoImpl() {

ParameterizedType superclass = (ParameterizedType) this.getClass().getGenericSuperclass();

//获得父类上声明的泛型数组

Type[] actualTypeArguments = superclass.getActualTypeArguments();

entityClass = (Class) actualTypeArguments[0];

}

public void save(T entity) {

this.getHibernateTemplate().save(entity);

}

public T findById(Serializable id) {

return this.getHibernateTemplate().get(entityClass, id);

}

public List findAll() {

String hql = "FROM " + entityClass.getSimpleName();

return (List) this.getHibernateTemplate().find(hql);

}

}

(2)、接下来,再看本项目中定义IBaseMapper

@SelectProvider注解用于生成查询用的sql语句,有别于@Select注解,@SelectProvide指定一个Class及其方法,并且通过调用Class上的这个方法来获得sql语句。

@ResultMap注解用于从查询结果集RecordSet中取数据然后拼装实体bean。

@SelectProvide方法,如果参数使用了@Param注解,那么参数在Map中以@Param的值为key

在这里使用了注解的形式,但是也可以在XMl方法配置。

public interface IBaseMapper {

@SelectProvider(type = MapperProvider.class, method = "dynamicSQL")

T selectOne(T record);

@SelectProvider(type = MapperProvider.class, method = "dynamicSQL")

T selectByPrimaryKey(Object key);

@InsertProvider(type = MapperProvider.class, method = "dynamicSQL")

int insert(T record);

...........................忽略了几个.......................

@DeleteProvider(type = MapperProvider.class, method = "dynamicSQL")

int delete(T record);

@DeleteProvider(type = MapperProvider.class, method = "dynamicSQL")

int deleteByPrimaryKey(Object key);

@DeleteProvider(type = MapperProvider.class, method = "dynamicSQL")

int deleteByExample(Object example);

@UpdateProvider(type = MapperProvider.class, method = "dynamicSQL")

int updateByExample(@Param("record") T record, @Param("example") Object example);

List getAllByPage(RowBounds rowBounds); //这个是用于分页的。

}

(3)、中间插一个RabbitMQ MSG序列化JSON转换器,主要作用是客户端和服务端需要传输Json格式的数据包,所以需要进行转换。这个工具包也是必备的之一。友情提示,安装MQ时,一定要以系统管理员运行CMD。

RabbitMQ已经实现了Jackson的消息转换(Jackson2JsonMessageConverter),由于考虑到效率,如下使用Gson实现消息转换。

如下消息的转换类的接口MessageConverter,Jackson2JsonMessageConverter的父类AbstractJsonMessageConverter针对json转换的基类。

我们实现Gson2JsonMessageConverter转换类也继承AbstractJsonMessageConverter。

为了节约地方,代码放Gist了,需要的时候直接去找。

/**

* MQ MSG序列化JSON转换器

*/

public class Gson2JsonMessageConverter extends AbstractJsonMessageConverter {

private static Logger logger = LoggerFactory.getLogger(Gson2JsonMessageConverter.class);

private static ClassMapper classMapper = new DefaultClassMapper();

private static Gson gson = new Gson();

@Override

protected Message createMessage(Object object, MessageProperties messageProperties) {

byte[] bytes = null;

try {

String jsonString = gson.toJson(object);

jsonString.getBytes(getDefaultCharset());

}

catch (IOException e) {

new MessageConversionException("Failed to convert Mesage context",e);

}

messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON);

messageProperties.setContentEncoding(getDefaultCharset());

if (bytes != null) {

messageProperties.setContentLength(bytes.length);

}

classMapper.fromClass(object.getClass(),messageProperties);

return new Message(bytes,messageProperties);

}

@Override

public ClassMapper getClassMapper() {

return new DefaultClassMapper();

}

}

(4)、接下来就是定义基础IBaseService以及实现类

public interface IBaseService {

/**

* 根据主键查询指定实体

*/

T getId(Object id) ;

List getByEntiry(T entity);

PageInfo getByPage(RowBounds rowBounds);

int save(T entity);

int update(T entity);

int delete(Object id);

int saveSelective(T entity) throws DBException;

int updateSelective(T entity);

}

IBaseService:全部代码在这Gist

/**

* Created by guo on 3/2/2018.

*/

public abstract class BaseService implements IBaseService {

private static Logger logger = LoggerFactory.getLogger(BaseService.class);

@Resource

protected RabbitTemplate amqpTemplate;

@Autowired

protected RedisTemplate redisTemplate;

public abstract IBaseMapper getBaseMapper();

/**

* 根据主键查询指定实体

* @param id

* @return

*/

@Override

public T getId(Object id) {

return this.getBaseMapper().selectByPrimaryKey(id);

}

/**

* 获取分页数据

*/

@Override

public PageInfo getByPage(RowBounds rowBounds) {

List list = this.getBaseMapper().getAllByPage(rowBounds);

return new PageInfo(list);

}

/**

* 保存对象,保存所有属性

*/

@Override

public int save(T entity) {

return this.getBaseMapper().insert(entity);

}

/**

* 删除指定数据

*/

@Override

public int delete(Object id) {

return this.getBaseMapper().deleteByPrimaryKey(id);

}

/**

* 更新对象,值更新对象中不为Null的属性,主键不能为NULL

*/

@Override

public int updateSelective(T entity) {

return this.getBaseMapper().updateByPrimaryKeySelective(entity);

}

}

(5)、接下来就是web包中的内容,涉及监听器和过滤器。

/**

* 系统初始化监听器,在系统启动时运行,进行一些初始化工作

*/

public class InitListener implements javax.servlet.ServletContextListener {

private static Logger logger = LoggerFactory.getLogger(InitListener.class);

public static ApplicationContext context;

public void contextDestroyed(ServletContextEvent arg0) {

}

public void contextInitialized(ServletContextEvent servletContextEvent) {

context = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext());

//加载银联upop配置文件

SDKConfig.getConfig().loadPropertiesFromSrc();

String proPath = servletContextEvent.getServletContext().getRealPath("/");

SDKConfig config = SDKConfig.getConfig();

config.setSignCertDir(proPath + config.getSignCertDir());

config.setSignCertPath(proPath + config.getSignCertPath());

config.setValidateCertDir(proPath + config.getValidateCertDir());

//缓存初始化忽略

}

}

过滤器:

我们先看关于日志的,真心看不懂,后面有一大堆。代码地址

/**

* request response log记录过滤器

*/

public class LoggingFilter extends OncePerRequestFilter {

protected static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class);

private static final String REQUEST_PREFIX = "Request: ";

private static final String RESPONSE_PREFIX = "Response: ";

private AtomicLong id = new AtomicLong(1);

@Override

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {

if (logger.isDebugEnabled()) {

long requestId = id.incrementAndGet();

request = new RequestWrapper(requestId, request);

}

try {

filterChain.doFilter(request, response);

} finally {

if (logger.isDebugEnabled()) {

logRequest(request);

}

}

}

//...

}

还有一个请求包装类,和响应类。。代码地址

public class RequestWrapper extends HttpServletRequestWrapper {

private final ByteArrayOutputStream bos = new ByteArrayOutputStream();

private long id;

public RequestWrapper(Long requestId, HttpServletRequest request) {

super(request);

this.id = requestId;

}

@Override

public ServletInputStream getInputStream() throws IOException {

return new ServletInputStream() {

private TeeInputStream tee = new TeeInputStream(RequestWrapper.super.getInputStream(), bos);

@Override

public int read() throws IOException {

return tee.read();

}

};

}

public byte[] toByteArray() {

return bos.toByteArray();

}

}

---------------------------------------------------------------------------------

public class ResponseWrapper extends HttpServletResponseWrapper {

private final ByteArrayOutputStream bos = new ByteArrayOutputStream();

private PrintWriter writer = new PrintWriter(bos);

private long id;

public ResponseWrapper(Long requestId, HttpServletResponse response) {

super(response);

this.id = requestId;

}

@Override

public ServletOutputStream getOutputStream() throws IOException {

return new ServletOutputStream() {

private TeeOutputStream tee = new TeeOutputStream(ResponseWrapper.super.getOutputStream(), bos);

@Override

public void write(int b) throws IOException {

tee.write(b);

}

};

}

@Override

public PrintWriter getWriter() throws IOException {

return new TeePrintWriter(super.getWriter(), writer);

}

public byte[] toByteArray() {

return bos.toByteArray();

}

}

这一块只是得补补,用到的时候再看,还有一个TeePrintWriter

核心包的东东算是完了,重点是在IBaseMapper、IBaseService的设计。这里用到了泛型,还有Mybatis3.X新特性,基于注解的。其实完全可以用XML配置文件。

gogogo 正式进入业务逻辑部分。

java 支付类的接口,Java后端支付大杂烩之core.dao,service,web(重点是接口的设计)(二)...相关推荐

  1. java对接支付宝微信银联_JavaWEB后端支付银联,支付宝,微信对接

    JavaWEB后端支付银联,支付宝,微信对接 标签(空格分隔): java 项目概述 最近项目需要后端打通支付,所以对接部分做成了一个小模块. 先说下项目要求: 后端要对接银联无跳转Token支付,支 ...

  2. java常用类的方法,java常用类的使用方法

    java常用类的使用方法 Interger:整数类型 1.属性. static int MAX_VALUE:返回最大的整型数: static int MIN_VALUE:返回最小的整型数: stati ...

  3. java测试类生成对象,java编写student类 用Java编写一段测试程序,生成student类的两个对象,并输出每个对象基本信息?...

    java中怎么创建对象数组?比如我创建了一个学生类Student,怎么用这个类创建一个对象数组,麻烦给个例子? 学生类:classA{privateStringnameprivateintagepub ...

  4. java引用公共类_使用键引用从Java公共类获取值 - java

    我们有一个Java公共类, public class Test { public class ob1 { public static final String test = "T1T1&qu ...

  5. java path类_基于java Files类和Paths类的用法(详解)

    Java7中文件IO发生了很大的变化,专门引入了很多新的类: import java.nio.file.DirectoryStream; import java.nio.file.FileSystem ...

  6. Java语言类的作用,java 语言Class类的作用,怎么使用?

    1,Class类有什么用? Class类的实例表示java应用运行时的类(Class ans enum)或接口(interface and annotation)(每个java类运行时都在JVM里表现 ...

  7. JAVA继承类phone_【Java基础】类-----继承

    一.基本知识 1.在Java语言中,实现类的继承使用extends关键字 格式如下: [public] class SubClass extends SuperClass{ //类体的定义 } 2.被 ...

  8. java final 类_在Java中,final修饰的类有什么特点

    展开全部 关于Java中的32313133353236313431303231363533e4b893e5b19e31333264663736final(2010-09-09 14:19:48)转载▼ ...

  9. java group类_浅析Java中线程组(ThreadGroup类)

    Java中使用ThreadGroup类来代表线程组,表示一组线程的集合,可以对一批线程和线程组进行管理.可以把线程归属到某一个线程组中,线程组中可以有线程对象,也可以有线程组,组中还可以有线程,这样的 ...

最新文章

  1. 每个程序员都应该知道的10件事!
  2. 掌握ConstraintLayout(十)按比例设置视图大小
  3. face recongnition
  4. Nginx upstream (一) 整体流程分析
  5. Orace用户创建及权限分配
  6. spss典型相关分析_R语言实战 多元统计分析Day10— —典型相关分析
  7. 《软件设计精要与模式》之Factory Method模式
  8. 表格如何excel在线转letex
  9. Vert.x(vertx)发送 HTTP/HTTPS请求
  10. 海康威视_摄像头搜索工具
  11. za压缩图片的几种方法
  12. 【复杂网络社团发现】Gephi绘制网络图
  13. led流水灯c语言程序移位,LED流水灯程序 移位写法
  14. 一个公司有m名推销员,他们都推销n种不同的产品。其中m>=l;m<=100,n>=l,n<=10。每天,每个推销员都要为售出的每一种产品交上来一个卡片。
  15. Could not resolve placeholder ‘project.version‘ in value “${project.version}”
  16. 左耳听风——笔记三:面试技巧
  17. post_thumbnail_html,WordPress 文章特色图片(Post Thumbnail)详细介绍和使用
  18. C语言-分支结构if-else
  19. 求10000以内所有的质数
  20. word中出现字与字之间的空白行无法删除

热门文章

  1. Project 'king.commons' is missing required library: 'lib/plweb.jar' Build path Build Path Problem
  2. CSS-float详解,深入理解clear:both[转+部分原创]
  3. HDU4609 FFT
  4. TechEd 2008 Developers: 新闻汇总
  5. Python之数据分析(卷积运算、移动均线、布林带)
  6. 计算机曝光模式有哪些,摄影:单反相机中P、A、S、M四种曝光模式的用法详解 -电脑资料...
  7. 外观模式和代理模式的联系和区别_设计模式之代理模式
  8. 中国大学MOOC“Python程序设计基础”第4次开课
  9. 时间都去哪儿了之Python程序测试与优化
  10. 1. InteliJ IDEA 下 的SpringBoot