目录
datasource和sessionfactorybean配置
项目介绍
从0搭建后端的Springboot+mybatis框架
实现后端的业务功能
实现本地微信小程序的前端开发
前端与后端的调控
技术储备要求
1.基础的java知识
2.基础的前端开发知识(简单了解HTML,JS等)
3.Spring,Mybatis基础知识(不会也没关系)
这里我要哭哭声明一件事,我为了大家能够更好的理解,在重新编辑的时候把每一部分的细节都写下来了,由于不是草稿箱,不能自动保存,我的电脑自动关机了,所以就都没了。于是我在文章的末尾大致总结了一下后端开发需要的工作,为了大家更好的理解。后期我有时间会把细节重新补上的呜呜呜QWQ...
项目设计及框架搭建
SpringBoot的搭建与启动上
SpringBoot的搭建与启动下
package com.example.demo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController//能够用来接受前台发来的请求,来做相应的数据处理
public class hello {
@RequestMapping(value = "/hello",method = RequestMethod.GET)//路由,告诉它怎么访问到这个方法
public String hello(){
return "Hello SpringBoot!";
}
}
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
更改访问端口:
server.port=8082
标准:项目名+方法名:
由于Springboot的高度封装性,所以我们很快就能完成项目的搭建
功能点的明确
我们要实现区域信息的增删改查
表设计与实体类的创建
首先数据库连接,创建表:
CREATE TABLE `tb_area` (
`area_id` int NOT NULL AUTO_INCREMENT,
`area_name` varchar(200) NOT NULL,
`priority` int NOT NULL DEFAULT '0',
`create_time` datetime DEFAULT NULL,
`last_edit_time` datetime DEFAULT NULL,
PRIMARY KEY (`area_id`),
UNIQUE KEY `UK_AREA` (`area_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
完成数据库实体类的创立。回到idea,我们在java包下创建一个entity包,新建Area类:
package com.example.demo.entity;
import java.util.Date;
public class Area {
//主键
private Integer areaId;
//名称
private String areaName;
//权重,越大越排前显示
private Integer pirority;
//创建时间
private Date creaTime;
//更新时间
private Date lastEditTime;
}
导入类:
创建实体类:(get/set可以快速设置)
package com.example.demo.entity;
import java.util.Date;
public class Area {
//主键
private Integer areaId;
//名称
private String areaName;
//权重,越大越排前显示
private Integer pirority;
//创建时间
private Date creaTime;
//更新时间
private Date lastEditTime;
public Integer getAreaId() {
return areaId;
}
public void setAreaId(Integer areaId) {
this.areaId = areaId;
}
public String getAreaName() {
return areaName;
}
public void setAreaName(String areaName) {
this.areaName = areaName;
}
public Integer getPirority() {
return pirority;
}
public void setPirority(Integer pirority) {
this.pirority = pirority;
}
public Date getCreaTime() {
return creaTime;
}
public void setCreaTime(Date creaTime) {
this.creaTime = creaTime;
}
public Date getLastEditTime() {
return lastEditTime;
}
public void setLastEditTime(Date lastEditTime) {
this.lastEditTime = lastEditTime;
}
}
项目开发
pom的配置、Dao层实现
如果报错:
Reload project。只有项目能启动,其他没有报错没有关系。
如果你的项目此时启动失败:可能是使用了外部数据库:那么需要设置数据库连接配置
mybatis-config的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 配置全局属性 -->
<settings>
<!-- 使用jdbc的getGeneratedKeys获取数据库自增主键值 -->
<setting name="useGeneratedKeys" value="true" />
<!-- 使用列标签替换列别名 默认:true -->
<setting name="useColumnLabel" value="true" />
<!-- 开启驼峰命名转换:Table{create_time} -> Entity{createTime} -->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
</configuration>
datasource和sessionfactorybean配置
package com.example.demo.config.dao;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import javax.sql.DataSource;
import java.io.IOException;
@Configuration
public class SessionFactoryConfiguration {
// mybatis-config.xml配置文件的路径
private static String mybatisConfigFile;
@Value("${mybatis_config_file}")
public void setMybatisConfigFile(String mybatisConfigFile) {
SessionFactoryConfiguration.mybatisConfigFile = mybatisConfigFile;
}
// mybatis mapper文件所在路径
private static String mapperPath;
@Value("${mapper_path}")
public void setMapperPath(String mapperPath) {
SessionFactoryConfiguration.mapperPath = mapperPath;
}
// 实体类所在的package
@Value("${type_alias_package}")
private String typeAliasPackage;
@Autowired
private DataSource dataSource;
/**
* 创建sqlSessionFactoryBean 实例 并且设置configtion 设置mapper 映射路径 设置datasource数据源
*
* @return
* @throws IOException
*/
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean createSqlSessionFactoryBean() throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置mybatis configuration 扫描路径
sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(mybatisConfigFile));
// 添加mapper 扫描路径
PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + mapperPath;
sqlSessionFactoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources(packageSearchPath));
// 设置dataSource
sqlSessionFactoryBean.setDataSource(dataSource);
// 设置typeAlias 包扫描路径
sqlSessionFactoryBean.setTypeAliasesPackage(typeAliasPackage);
return sqlSessionFactoryBean;
}
}
#Mybatis
mybatis_config_file=mybatis-config.xml
mapper_path=/mapper/**.xml
type_alias_package=com.imooc.demo.entity
dao的创建
package com.example.demo.dao;
import java.util.List;
import com.example.demo.entity.Area;
public interface AreaDao {
/**
* 列出区域列表
*
* @return areaList
*/
List<Area> queryArea();//返回AreaList(),查询
有一次返回所有area信息,也有返回单条的,
/**
* 根据Id列出具体区域
*
* @return area
*/
Area queryAreaById(int areaId);//传入id来获取单条区域信息
/**
* 插入区域信息
*
* @param area
* @return
*/
int insertArea(Area area);
/**
* 更新区域信息
*
* @param area
* @return
*/
int updateArea(Area area);
/**
* 删除区域信息
*
* @param areaId
* @return
*/
int deleteArea(int areaId);//传入id,根据id删除
}
mapper的编写
来完成orm,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.dao.AreaDao">//指定对应的dao,就会去实现里面对应的方法
<select id="queryArea" resultType="com.example.demo.entity.Area">//返回的是list
//下面就是写对应的sql语句
SELECT area_id, area_name,
priority, create_time, last_edit_time
FROM tb_area
ORDER BY priority
DESC
</select>
<select id="queryAreaById" resultType="com.example.demo.entity.Area">//返回的是单条,mybatis会自动判断。
SELECT area_id, area_name,
priority, create_time, last_edit_time
FROM tb_area
WHERE
area_id=#{areaId}//传入的id,
</select>
<insert id="insertArea" useGeneratedKeys="true" keyProperty="areaId"//如果insert成功,返回主键的值,即area_id
keyColumn="area_id" parameterType="com.example.demo.entity.Area">
INSERT INTO
tb_area(area_name,priority,
create_time,last_edit_time)
VALUES
(#{areaName},#{priority},
#{createTime},#{lastEditTime})
</insert>
<update id="updateArea" parameterType="com.example.demo.entity.Area">
update tb_area
<set>
<if test="areaName != null">area_name=#{areaName},</if>//当我们的属性area_name不为空时,我们的area_name就需要改变,就给它set上。
<if test="priority != null">priority=#{priority},</if>
<if test="lastEditTime != null">last_edit_time=#{lastEditTime}</if>//我们最新的改变时间
</set>
where area_id=#{areaId}//确定唯一性
</update>
<delete id="deleteArea">
DELETE FROM
tb_area
WHERE
area_id =
#{areaId}
</delete>
</mapper>
dao层的开发
编写单元测试类对五个方法进行验证
Alt+Enter
import com.example.demo.entity.Area;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Date;
import java.util.List;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING) // 按方法名大小升序执行
public class AreaDaoTest {
//通过spring容器注入Dao的实现类
@Autowired
private AreaDao areaDao;
@Test
public void queryArea() {
List<Area> areaList = areaDao.queryArea();
// 验证预期值和实际值是否相符
assertEquals(2, areaList.size());
}
@Test
public void insertArea() {
//创建一个区域对象
Area area = new Area();
area.setAreaName("测试区域");
area.setCreateTime(new Date());
area.setPriority(1);
//将该对象实例添加入库
int effectedNum = areaDao.insertArea(area);
//检测影响行数
assertEquals(1, effectedNum);
//校验总数是否+1
List<Area> areaList = areaDao.queryArea();
assertEquals(3, areaList.size());
}
@Test
public void queryAreaById() {
Area area = areaDao.queryAreaById(2);
assertEquals("东苑", area.getAreaName());
}
@Test
public void updateArea() {
List<Area> areaList = areaDao.queryArea();
for (Area area : areaList) {
if ("测试区域".equals(area.getAreaName())) {
// 对比之前的priority值
assertEquals(1, area.getPriority().intValue());
area.setPriority(2);
int effectedNum = areaDao.updateArea(area);
assertEquals(1, effectedNum);
}
}
}
@Test
public void deleteArea() {
List<Area> areaList = areaDao.queryArea();
for (Area area : areaList) {
if ("测试区域".equals(area.getAreaName())) {
int effectedNum = areaDao.deleteArea(area.getAreaId());
assertEquals(1, effectedNum);
}
}
// 重新获取一次列表,看看总数是否少1
areaList = areaDao.queryArea();
assertEquals(2, areaList.size());
}
}
service层的实现
用来整合复杂的业务逻辑
配置:
package com.example.demo.config.serivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import javax.sql.DataSource;
/**
* 对标spring-service里面的transactionManager
* 继承TransactionManagementConfigurer是因为开启annotation-driven
*
* @author xiangze
*
*/
@Configuration
// 首先使用注解 @EnableTransactionManagement 开启事务支持后
// 在Service方法上添加注解 @Transactional 便可
@EnableTransactionManagement
public class TransactionManagementConfiguration implements TransactionManagementConfigurer {
@Autowired
// 注入DataSourceConfiguration里边的dataSource,通过createDataSource()获取
private DataSource dataSource;
@Override
/**
* 关于事务管理,需要返回PlatformTransactionManager的实现
*/
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new DataSourceTransactionManager(dataSource);
}
}
接着要去实现Service层的接口,它的方法与Dao层保持一致,注:这里纯属巧合,有时候一个类囊括了不同Dao层各类方法。
package com.example.demo.service;
import com.example.demo.entity.Area;
import java.util.List;
public interface AreaService {
/**
* 获取区域列表
*
* @return
*/
List<Area> getAreaList();
/**
* 通过区域Id获取区域信息
*
* @param areaId
* @return
*/
Area getAreaById(int areaId);
/**
* 增加区域信息
*
* @param area
* @return
*/
boolean addArea(Area area);
/**
* 修改区域信息
*
* @param area
* @return
*/
boolean modifyArea(Area area);
/**
* 删除区域信息
*
* @param areaId
* @return
*/
boolean deleteArea(int areaId);
}
接着去写我们的实现类:
package com.example.demo.service.impl;
import com.example.demo.dao.AreaDao;
import com.example.demo.entity.Area;
import com.example.demo.service.AreaService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
@Service
public class AreaServiceImpl implements AreaService {
@Autowired
private AreaDao areaDao;
@Override
public List<Area> getAreaList() {
// 返回所有的区域信息
return areaDao.queryArea();
}
@Override
public Area getAreaById(int areaId) {
return areaDao.queryAreaById(areaId);
}
@Transactional
@Override
public boolean addArea(Area area) {
// 空值判断,主要是判断areaName不为空
if (area.getAreaName() != null && !"".equals(area.getAreaName())) {
// 设置默认值
area.setCreateTime(new Date());
area.setLastEditTime(new Date());
try {
int effectedNum = areaDao.insertArea(area);
if (effectedNum > 0) {
return true;
} else {
throw new RuntimeException("添加区域信息失败!");
}
} catch (Exception e) {
throw new RuntimeException("添加区域信息失败:" + e.toString());
}
} else {
throw new RuntimeException("区域信息不能为空!");
}
}
@Transactional
@Override
public boolean modifyArea(Area area) {
// 空值判断,主要是areaId不为空
if (area.getAreaId() != null && area.getAreaId() > 0) {
// 设置默认值
area.setLastEditTime(new Date());
try {
// 更新区域信息
int effectedNum = areaDao.updateArea(area);
if (effectedNum > 0) {
return true;
} else {
throw new RuntimeException("更新区域信息失败!");
}
} catch (Exception e) {
throw new RuntimeException("更新区域信息失败:" + e.toString());
}
} else {
throw new RuntimeException("区域信息不能为空!");
}
}
@Transactional
@Override
public boolean deleteArea(int areaId) {
if (areaId > 0) {
try {
// 删除区域信息
int effectedNum = areaDao.deleteArea(areaId);
if (effectedNum > 0) {
return true;
} else {
throw new RuntimeException("删除区域信息失败!");
}
} catch (Exception e) {
throw new RuntimeException("删除区域信息失败:" + e.toString());
}
} else {
throw new RuntimeException("区域Id不能为空!");
}
}
}
Colltroller层的实现
业务Colltorller方法的实现
统一异常类处理
package com.example.demo.web;
import com.example.demo.entity.Area;
import com.example.demo.service.AreaService;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/superadmin")
public class AreaController {
@Autowired
private AreaService areaService;
/**
* 获取所有的区域信息
*
* @return
*/
@RequestMapping(value = "/listarea", method = RequestMethod.GET)
private Map<String, Object> listArea() {
Map<String, Object> modelMap = new HashMap<String, Object>();
List<Area> list = new ArrayList<Area>();
// 获取区域列表
list = areaService.getAreaList();
modelMap.put("areaList", list);
return modelMap;
}
/**
* 通过区域Id获取区域信息
*
* @return
*/
@RequestMapping(value = "/getareabyid", method = RequestMethod.GET)
private Map<String, Object> getAreaById(Integer areaId) {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 获取区域信息
Area area = areaService.getAreaById(areaId);
modelMap.put("area", area);
return modelMap;
}
/**
* 添加区域信息
*
* @param area
* @return
* @throws IOException
* @throws JsonMappingException
* @throws JsonParseException
*/
@RequestMapping(value = "/addarea", method = RequestMethod.POST)
private Map<String, Object> addArea(@RequestBody Area area)
throws JsonParseException, JsonMappingException, IOException {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 添加区域信息
modelMap.put("success", areaService.addArea(area));
return modelMap;
}
/**
* 修改区域信息,主要修改名字
*
* @param area
* @return
* @throws IOException
* @throws JsonMappingException
* @throws JsonParseException
*/
@RequestMapping(value = "/modifyarea", method = RequestMethod.POST)
private Map<String, Object> modifyArea(@RequestBody Area area)
throws JsonParseException, JsonMappingException, IOException {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 修改区域信息
modelMap.put("success", areaService.modifyArea(area));
return modelMap;
}
@RequestMapping(value = "/removearea", method = RequestMethod.GET)
private Map<String, Object> removeArea(Integer areaId) {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 修改区域信息
modelMap.put("success", areaService.deleteArea(areaId));
return modelMap;
}
}
统一异常处理类
处理controll、service以及dao可能出现的异常
与前端做交互
package com.example.demo.handler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 统一异常处理类
*
* @author xiangze
*
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String, Object> exceptionHandler(HttpServletRequest req, Exception e) throws Exception {
Map<String, Object> modelMap = new HashMap<String, Object>();
modelMap.put("success", false);
modelMap.put("errMsg", e.getMessage());
return modelMap;
}
}
总结
首先我们要通过navicat创建一个数据库表出来。返回我们的idea,创建一个数据库的实体类 写在entity包下,叫它Area,这个类主要完成数据库的实体化,它的成员对应数据库的字段,然后完成我们就基础的set和get操作。
pom配置,即里面涉及到了meavn配置等
紧接着我们这个项目用到了mybatis.cml
里面主要是一些mybatis的规范,包括
使用我们jdbc的方法来获取数据库自增主键值,还有列标签替换列别名,还有驼峰命名转换,就是可以把sql那个语言,转化成我们实体类中的对应成员。
然后就开始我们的数据库连接了哈
1. 创建了一个dataSourceConfiguration类
首先就是spring里有一个ioc容器aop容器。
然后我们创建一个bean给它起别名叫dataSource,有两个检索的一个是告诉spring需要到这个类去检索这个bean,还有一个就是配置mybatis mapper的扫描路径。
创建完相当于我们的ioc里面有了一个bean叫dataSource,然后这个bean返回的是数据库的连接池。然后我们要建一个这个dataSource的实体类,然后去设置它的驱动,本地连接,还有我们的用户名,密码等。这些东西需要去我们的配置文件里写,写它具体的驱动,还有具体的内容。我们的这个类通过@value+配置文件里对应的名字,往这个bean里面注入内容。
2.创建一个提交事务的类
这个类也要创建以后bean,我理解的是将mybatis和dataSource进行捆绑,将它实体化之后,要设置mybatis的扫描路径,mapper的扫描路径,设置它的数据源就是把dataSource放进去,还有一个设置要将它映射实体类。
接着就开始dao的创建了,首先是创建它的接口哈,接口里面写的是抽象方法,不需要实现。对应的就是增删改查。
接着就是mapper,我们在这里面写一个.xml文件,里面具体就是实现我们dao层的增删改查。
select 里面的id对应接口里的抽象方法哈,返回参数就是我们的实体类。然后我们的的sql语句里,不管是value后面跟着的还是where后面获取的都是#{….},里面填写的就是我们实体类里的成员哈。它这里的update,做了判断表里字段是不是非空,不是非空就把你写的赋值进去。
所以mapper实现的就是一个规范,把数据库语言转化成我们的程序能够理解的,是双向的哈。就是两边都能互相理解。
接着就是写一个单元测试类,对这个五个方法进行验证
要在前面@runwith…、
然后我们在类里创建一个AreaDao接口类的成员,通过@Autowired注入。
后面的方法就是增删改查四个哈,在方法里创建区域对象,然后通过set,get去测试。里面有一个叫asserEquals的是用来判断返回结果是不是符合预期值的。
还有一个叫effectedNum,是在我们往里面增加一条数据或者更新一条数据的时候会进行一个+1,最后放到asserEquals来测试。
接着到我们的Service层
因为service是dao层的一个封装,所以会有一个事务管理操作。
然后我们创建的这个类是继承TransactionMangrmentConfiguration的,
然后我们要注入datasource。
然后我们开始写一个它的接口,这里对应的抽象方法和我们的dao层一一对应的哈。(只是这里一一对应,但是当一个service对应很多dao,所以就会不一样)
然后开始写service的实现类,记得要写implements,是我们接口的一个实现哈。
这里我们要注入的就是AreaDao接口的一个成员,我们这里的方法对应的是接口里的抽象方法哈 它是可以去返回 我们通过dao层的方法,得到的数据 然后这里是进行逻辑业务的嘛
后面的方法要判断它的区域名、id号是否为空。这里就用到了try catch throw。
最后就是我们的Controler层,然后写一个类,我们要注入的是AreaService接口类的一个成员。
最后写了一个统一异常处理的类。