企业级后台接口开发。环境基于spring+springboot+springmvc+mybatis。测试 junit4

上一篇博文主要讲了一下基于http协议的接口框架搭建。主要就是spring+springboot+springmvc+mybatis的框架整合。

上篇环境配置的地址:http://blog.csdn.net/qq_36068028/article/details/76571531

其实这些框架整合,或者说环境搭建。往往你在进入企业的时候就已经搭建好了。你只需要在springboot的配置文件中配置好参数。这样你就可以实现与数据库的数据交互和与前端的信息交互。那么作为一名程序员我们要做些什么呢?

答案来了

实现业务逻辑。

可能你觉得这有些空泛。那么请看下面。

在解释实现业务逻辑之前,我要先讲一下MVC的概念。M(model)模型,V(view)视图,C(controller)控制器。借用别人的一句话,它是一种业务逻辑,数据,界面显示分离的方法组织代码。 

这里又提及了一遍业务分离。如果看了我上篇的博文。相信你一定会认识到业务分离的重要性。接下来我的接口开发文档代码也时刻遵守着这个规则。

那么,我刚刚讲的那么多和我的接口开发有什么联系呢?

承接上面所讲。mvc将一个业务分成来3个部分。因为我的题目是后台接口开发。所以我不需要关心界面显示部分(因为我开发的是后台接口开发,前端的界面显示部分由前端工程师来考虑。这一切基于业务的分离。)如果你还是不理解。我接下贴一张图希望你能好好理解。

企业级后台接口开发。环境基于spring+springboot+springmvc+mybatis。测试 junit4_第1张图片

如果你还是觉得光看图还是觉得内容空泛,无法理解。

那么请参考书籍HeadFirst(设计模式)第一章。(内容绝对不会让你失望!!!)

那么我上面讲的这么多是为了什么呢

我的目的在于:让编程者理解 业务分离 面向接口 的重要性。
如果这两点你不懂。接下去的代码即使你全都看懂了,你仍然会产生以下疑问:
1.我在做什么?
2.我做好的东西怎么调用?
3.为什么我要这么做而不用别的方法?
所以在看下面的代码之前,你一定要搞懂以下知识清单

1.Servlet 

2.面向接口概念

3.Spring依赖注入和面向切面

4.mybatis数据库操作

5.mvc模式

6.json数据格式

如果这些你都有了粗浅的理解。并且也有基本的java基础。那么恭喜你!!!你可以上车了

      一切的开始——阅读接口文档和数据库结构

接下来上接口数据库文档(只需要关注activty表,activityjumpurl表,activiyty)

http://pan.baidu.com/s/1hs9spiG

      还有我的代码文档

在导入文档前请先配置好Gradle,要么就直接用记事本看也不错

http://pan.baidu.com/s/1c2J9JLQ

请在写代码之前阅读认真阅读接口文档。接下来上代码讲解。

这次的代码不会像上篇博文一样做通篇的解读。我只讲具体实现业务逻辑的部分。

Dao层

package cn.icom.business.mapper;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;

import cn.icom.business.entity.po.getActivity_2;
import cn.icom.business.entity.po.getActivitys_1;
import cn.icom.business.entity.po.urls;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by asdsas,faksaldpsaldpasldpsalds
 */
@Component

public interface UserMapper {
	//活动列表(分页)
	public List getActivitys(@Param("activityId") int activityId,@Param("size") int size);
	//活动详情
	public List getActivity123(int activityId);
	//新增活动,要将数据插入4个表所以写四条插入语句 ,并且要在期中一条中返回一个activityid
	public int saveactivity(Map map);//condition是map的大集合,Map相当于是通过keyvalue方式插入一个数据
	public void saveactivityVisibleRangeOrg(Map map);
	public void saveactivityVisibleRangeEmp(Map map);
	public int saveactivityJumpUrl(ArrayList> list);
	//修改活动
	public void updateactivity(Map map);
	//测试数据库连接性
	public String fortest(int activityId);
	//修改活动=先删除,再插入
	public void deleteactivityVisibleRangeEmp(Map map);
	public void deleteactivityVisibleRangeOrg(Map map);
	public void deleteactivityJumpUrl(Map map);

}












这层是接口层,负责连接之后的mapper.xml来实现对数据库的操作。也提供接口,让业务层负责调用。

Mapper.xml






    
    
    
     
    
    
    
    
    
    
    
    
    
    
	
	    insert into activityVisibleRangeOrg(activityId,orgId,createDate) values
	    
	       (#{activityId},#{item},#{createDate})
	    	    
	
	
	
	    insert into activityVisibleRangeEmp(activityId,eId,createDate) values
	    
	       (#{activityId},#{item},#{createDate})
	        
	
	
	    insert into activity(title,subTitle,fileKey,summary,beginDate,endDate,createrId,createDate) values
	       (#{title},#{subTitle},#{fileKey},#{summary},#{beginDate},#{endDate},#{createrId},#{createDate}) 
	
	
	
	    insert into activityJumpUrl(activityId,type,url,createDate) values    
	     
	    
	      
	        (#{item.activityId},#{item.type},#{item.url},#{item.createDate})        	        
	    
	
	
	
		UPDATE activity 
		title = #{title},subTitle = #{subTitle},fileKey = #{fileKey},summary = #{summary},beginDate = #{beginDate},endDate = #{endDate},createDate = #{endDate}
		 
		 WHERE activityId=#{activityId}
	
	
		 
		     UPDATE activityVisibleRangeOrg 
				 
		orgId=#{item},createDate=#{createDate}
		
		 WHERE activityId=#{activityId}
	
	
	
	    
		UPDATE activityVisibleRangeEmp
		  
		 eId=#{item},createDate=#{createDate}	 
		 
		 WHERE activityId=#{activityIds}
		 
	
	 
	    
	    	update activityJumpUrl
	    	    
	    	    type=#{item.type},url=#{item.url},createDate=#{item.createDate}	    	   
	           
	         WHERE activityId=#{item.activityId}	        
	    	    
	
	
	
	     delete from activityVisibleRangeEmp where activityId=#{activityId}	    
	
	
	
	    delete from activityVisibleRangeOrg where activityId=#{activityId}
	    
	
	
	
	    delete from activityJumpUrl where activityId=#{activityId}	    
	
	
    
这层是实现通过mybatis来实现对数据库的操作。注意标签。这是实现批量插入的语句。至于参数怎么传,数据怎么接。还是自行百度吧。否则又是一篇博文。

测试

下文的代码全都打了注释,当你需要测试的时候把注释去掉即可。

因为上篇博文没有将测试这一层,所以在这里我想要好好讲一下。

在这里我要讲一下junit4这个东西。

我想借用百度百科上的一句话:junit是一个java语言的单元测试框架。

我的理解是这样的:前面我一直重复的面向接口和业务分离。目的是为了什么?就是为了将工作细化从而能够将一个工作分成不同的模块让大伙通力合作。

但是,这存在一个问题。

那就是:你如何将不同的人的代码合起来组成一个工程?如果大家各写各的而不做测试。这很可能导致无法与他人的代码形成对接。

所以我直接引出我的理解:测试是一种以模拟他人的操作的方式,来验证自己代码是否能够形成对接的操作。

举个例子:一个项目比如说有一个数据库架构师,后台开发工程师,和一个前端工程师

作为后台开发人员,你要做以下几件事

1.从前端接数据

2.在自己的service层处理数据,从而能够实现客户需求

3.将自己的数据传入到数据库,从而实现增删改查

那么你不得不与前端和数据库发生数据交互。

如果有一天你代码写完了,而前端的人甚至还没有开始写代码。那么,你不得不根据之前写好的接口文档(看上面百度云接口文档链接),来模拟前端数据的输入。从而测试自己的代码逻辑是否能实现。

而junit4它恰巧是一款操作简洁的优秀测试库框架,并且spring也对它有较好的集成。

所以,以上就是我对 为什么要测试和为什么要用junit4做测试的解释。


package cn.icom.business.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;

import cn.icom.business.service.*;
import cn.icom.business.mapper.UserMapper;
import cn.icom.business.Application;
import cn.icom.business.entity.po.getActivity_2;
import cn.icom.business.entity.po.getActivitys_1;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * Created by asdsas,faksaldpsaldpasldpsalds
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class activitytest{
@Autowired
UserMapper UserMapper;
//测试插入
/*
@Test
public void test3(){
	HashMap map1=new HashMap();
	long createDate=System.currentTimeMillis();
	map1.put("title", "lalala");
	map1.put("subTitle", "lalala");
	map1.put("fileKey", "lalala");
	map1.put("summary", "lalala");
	map1.put("beginDate", "10086");
	map1.put("endDate", "10086");
	map1.put("createrId", "123");
	map1.put("createDate",createDate );
	UserMapper.saveactivity(map1);
	System.out.println(map1.get("activityId"));
	String[] tollgateIds=new String[]{"abc","def","ghi"};
	HashMap map = new HashMap();
	map.put("eIds", tollgateIds);
	map.put("createDate", createDate);
	map.put("activityId",map1.get("activityId"));
	UserMapper.saveactivityVisibleRangeEmp(map);
	HashMap map2 = new HashMap();
	map2.put("orgIds", tollgateIds);
	map2.put("createDate", createDate);
	map2.put("activityId",map1.get("activityId"));
	UserMapper.saveactivityVisibleRangeOrg(map2);
	ArrayList> list=new ArrayList>();
	HashMap urls = new HashMap();
	urls.put("activityId",map1.get("activityId"));
	urls.put("type", 10086);
	urls.put("createDate", createDate);
	urls.put("url", "abc");
	list.add(urls);
	UserMapper.saveactivityJumpUrl(list);	 
	}
	*/
//插入功能已实现

//更新功能测试
	@Test
	public void test4(){
		/*HashMap map1=new HashMap();
		long createDate=System.currentTimeMillis();
		map1.put("title", "lalala");
		map1.put("subTitle", "lalala");
		map1.put("fileKey", "lalala");
		map1.put("summary", "lalala");
		map1.put("beginDate", "10086");
		map1.put("endDate", "10086");
		map1.put("activityId", "18");
		map1.put("createDate",createDate );
		UserMapper.updateactivity(map1);*/
		//测试delete eid
		//HashMap map1=new HashMap();
		//map1.put("activityId", "20");
		//UserMapper.deleteactivityVisibleRangeEmp(map1);
		//测试delete orgId
		//UserMapper.deleteactivityVisibleRangeOrg(map1);
		//测试delete delete urls
		/*HashMap urls = new HashMap();
		urls.put("activityId","15");
		UserMapper.deleteactivityJumpUrl(urls);*/
		
		
	}


}

   这层的目的在于测试后台的mapper.xml和dao层接口的通力配合下。是否能对数据库进行正确的操作。至于具体如何连上数据库。请看文档的config层,和spring的配置文件properities.

service层

这层主要是
package cn.icom.business.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import cn.icom.business.mapper.UserMapper;
import cn.icom.icommon.protocol.DataResult;
import cn.icom.business.entity.po.getActivitys_1;
import cn.icom.business.entity.po.getActivity_2;
import cn.icom.business.entity.po.sendActivity;
import cn.icom.business.entity.po.urls;
import cn.icom.business.entity.po.addactivity;
/**
 * Created by asdsas,faksaldpsaldpasldpsalds
 */
@Service
public class getActivitys {
	@Autowired
	UserMapper usermapper;
	//活动列表(分页)
	public DataResult getActivityss(JSONObject param){
		int activityId=param.getInteger("activityId");
		int size=param.getInteger("size");
		if(StringUtils.isBlank(param.getString(String.valueOf(param.getInteger("activityId"))))||StringUtils.isBlank(param.getString(String.valueOf(param.getInteger("size"))))){
			return new DataResult(1000,"输入参数错误");		
		}
		List getActivitys_1=usermapper.getActivitys(activityId, size);
		return new DataResult(getActivitys_1);
	}
	//活动详情
	public DataResult getActivity(JSONObject param){
		
		if(StringUtils.isBlank(String.valueOf(param.getString("activityId")))){
			return new DataResult(1000,"输入参数错误");	
		}
		int activityId=param.getIntValue("activityId");
		List getActivity_2=usermapper.getActivity123(activityId);
		getActivity_2 abcd;
		//在数据库表中activityid可能会对应多个orgIds,eIds,type,url要把取来的数据遍历一遍再发到前端
		String[] orgIds=new String[100000];
		String[] eIds=new String[100000];
		int type;
		String url;
		JSONArray urls=new JSONArray();
		Map map6 = new HashMap();
		//一次查询只是对应一条orgid,eid这里也要把查询到的条数全部存到数组里再发到前端
		for(int i=0;i中位置为0的数据即可
		abcd=getActivity_2.get(0);
		String title=abcd.getTitle();
		String subTitle=abcd.getSubTitle();
		String fileKey=abcd.getFileKey();
		String summary=abcd.getSummary();
		Long beginDate=abcd.getBeginDate();
		Long endDate=abcd.getEndDate();
		//因为从数据库传来的数据格式和返回给前端的数据结构格式是不一样的这里要把整理好的数据包装成一个新的实体类返回给前端
		addactivity addactivity=new addactivity(activityId, title, subTitle, fileKey, summary, beginDate, endDate, orgIds, eIds, urls);
		return new DataResult(addactivity);
	}
	//插入数据
	public DataResult save(JSONObject param){
		long createDate=System.currentTimeMillis();
		if(StringUtils.isBlank(String.valueOf(param.getIntValue("activityId")))||StringUtils.isBlank(param.getString("subTitle"))||StringUtils.isBlank(param.getString("summary"))||StringUtils.isBlank(String.valueOf(param.getLongValue("beginDate")))){
			return new DataResult(1000,"输入参数错误");		
		}
		
		//把前端传过来的数据先转成string[]
		//处理orgIds数组
		JSONArray abc=param.getJSONArray("orgIds");
		String[] orgIds=new String[700515];
		for(int i=0;i map = new HashMap();
		map.put("createDate", createDate);
		map.put("createrId",param.getString("createrId"));
		map.put("title",param.getString("title"));
		map.put("subTitle", param.getString("subTitle"));
		map.put("fileKey", param.getString("fileKey"));
		map.put("summary", param.getString("summary"));
		map.put("beginDate", param.getLongValue("beginDate"));
		map.put("endDate",param.getLongValue("endDate"));
		usermapper.saveactivity(map);
		//插入activityVisibleRangeOrg表
		Map map1 = new HashMap();
		map1.put("orgIds", orgIds);
		map1.put("createDate", createDate);
		map1.put("activityId",map.get("activityId"));
		usermapper.saveactivityVisibleRangeOrg(map1);
		//插入activityVisibleRangeEmp表
		Map map2 = new HashMap();
		map2.put("eIds", eIds);
		map2.put("createDate", createDate);
		map2.put("activityId",map.get("activityId"));
		usermapper.saveactivityVisibleRangeEmp(map2);
		
		//插入activityJumpUrl表
		ArrayList> list=new ArrayList>();//list中的一个元素是以map为单位的
		 HashMap urls = new HashMap();  
		 JSONArray jsonArray = param.getJSONArray("urls");
		 int size2=jsonArray.size();
		 for(int i=0;i mapp=new HashMap();
		mapp.put("activityId",param.getString("activityId"));
		//更新activity表
		Map map = new HashMap();
		map.put("createDate", createDate);
		map.put("activityId",param.getString("activityId"));
		map.put("title",param.getString("title"));
		map.put("subTitle", param.getString("subTitle"));
		map.put("fileKey", param.getString("fileKey"));
		map.put("summary", param.getString("summary"));
		map.put("beginDate", Long.parseLong(param.getString("beginDate")));
		map.put("endDate", Long.parseLong(param.getString("endDate")));
		usermapper.updateactivity(map);		
		//更新activityVisibleRangeOrg表
		Map map1 = new HashMap();
		map1.put("activityId",param.getString("activityId"));
		map1.put("orgIds", orgIds);
		map1.put("createDate", createDate);
		//先删除之前对应的ActivityId内对应表中字段
		usermapper.deleteactivityVisibleRangeOrg(mapp);
		//再新增前端传来的新的活动
		usermapper.saveactivityVisibleRangeOrg(map1);
		//更新activityVisibleRangeEmp表
		HashMap map2 = new HashMap();
		map2.put("activityId",param.getString("activityId"));
		map2.put("eIds", eIds);
		map2.put("createDate", createDate);
		//先删除之前对应的ActivityId内对应表中字段
		usermapper.deleteactivityVisibleRangeEmp(mapp);
		//再新增前端传来的新的活动
		usermapper.saveactivityVisibleRangeEmp(map2);
		//更新activityJumpUrl表
		ArrayList> list=new ArrayList>();
		HashMap urls = new HashMap();
		JSONArray jsonArray = param.getJSONArray("urls");
		int size2=jsonArray.size();
		for(int i=0;i>),然后通过map传给mybatis.这样在mapper.xml中就可以用#{}来处理。而且还不用另外写实体类
	//所有从数据库中取来的数据要在业务层重新包装成前端需要的数据结构类型。然后务必写一个实体类来存储取来后经过业务层包装的数据,最后返回给前端。
	//
    //insert into saveactivityVisibleRangeEmp(eId,createDate) values
    //
    //  (#{item},#{createDate})
    //     
	//
	//mybatis批量注入的意义在于不用一次一次的写增删该查的语句 parameterType代表输入参数类型(我这边指定的是HashMap)
	//parameterType若是hashmap则在collection中用在service层定义的key eIds
	
}
return new dataresult();这条语句用了很多次。它的目的就是传给前端dataresult()信息(这体现了业务分离的思想,详细点说,那就是:前端只关注后端dataresult()函数传来的值,并不关心后台逻辑是什么)。dataresult是什么呢。请摁下ctrl鼠标左键点dataresult自行理解。

controller层

package cn.icom.business.controller;

import cn.icom.business.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;

import cn.icom.business.service.getActivitys;
import cn.icom.icommon.protocol.DataResult;

import java.util.List;

@RestController
public class RegController {
    @Autowired
    getActivitys getActivitys;
    //活动列表(分页)
    @RequestMapping(value = "/getActivitys")
    public DataResult getActivitys(@RequestBody JSONObject param) {
        return getActivitys.getActivityss(param);
    }
    @RequestMapping(value = "/getActivity")
    public DataResult getActivity(@RequestBody JSONObject param){
    	return getActivitys.getActivity(param);
    }
    @RequestMapping(value = "/addActivity")
    public DataResult addActivity(@RequestBody JSONObject param){
    	return getActivitys.save(param);
    } 
    @RequestMapping(value = "/editActivity")
    public DataResult editActivity(@RequestBody JSONObject param){
    	return getActivitys.update(param);
    } 
    

}

这层的代码很少,主要就是调用上面service层写好的接口(体现业务分离思想)。打个比方。下次活动我还有类似这次活动的需求。我只需要传入对口的参数,这个写好的接口就可以用到别的逻辑上。这就是面向接口。而面向对象并没有实现业务分离。这就导致下次还有类似需求的时候你不得不重写一遍方法。

结语

        如果我上面所说的你已经掌握不少了的话,那么你已经拥有了开发项目的能力了。接下来便是不断学习具体实现的新方法和不断实践不怕调bug的心态。





这层的目的在于测试后台的mapper.xml和dao层接口的通力配合下。是否能对数据库进行正确的操作。至于具体如何连上数据库。请看文档的config层,和spring的配置文件properities.

你可能感兴趣的:(企业级后台接口开发。环境基于spring+springboot+springmvc+mybatis。测试 junit4)