文章目录
- 前言
- 项目展示:
- 一、项目设计及框架搭建
- 1、SpringBoot搭建
- 2、表设计与实体类的创建
- 二、项目开发
- 1、pom配置
- 2、MyBatis配置
- 3、datasource和sessionfactorybean的配置
- 4、dao的创建
- 5、mapper的编写
- 6、dao层开发
- 7、service层的实现
- 8、业务controller方法的实现
- 9、统一异常功能的实现
- 三、微信小程序的前端入门
- 1、list.js
- 2、list.json
- 3、list.wxml
- 4、list.wxss
- 四、总结
前言
由于对微信小程序的好奇心驱动,便学习了一个简单的搭建迷你微信小程序的小项目,后端主要用到了SpringBoot+MyBatis技术,而微信小程序的前端主要用到了Vue框架的技术和对微信开发者工具的简单使用。
项目展示:
一、项目设计及框架搭建
1、SpringBoot搭建
在IDEA中创建Spring Initializr,
2、表设计与实体类的创建
创建数据库名demo,运行下列sql语句:
CREATE TABLE tb_area (
area_id int(2) NOT NULL auto_increment,
area_name varchar(200) NOT NULL,
priority int(2) 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 AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
实体类com/dem/entity/ Area.java:(get、set)
public class Area {
//主键ID
private Integer areaId;
//名称
private String areaName;
//权重,越大越排前显示
private Integer priority;
//创建时间
private Date createTime;
//更新时间
private Date lastEditTime;
}
二、项目开发
1、pom配置
<!-- mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 连接池-->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
2、MyBatis配置
mybatis-config.xml:
<?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>
3、datasource和sessionfactorybean的配置
这个datasource数据库连接是很麻烦的,我们可以直接在application.properties进行配置:
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
spring.datasource.username = root
spring.datasource.password = 1214
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driverspring.datasource.max-active=20 //指定连接池中最大的活跃连接数
spring.datasource.max-idle=8 //指定连接池中连接的最大的空闲连接数量
spring.datasource.min-idle=8 //指定必须保持连接的最小值
spring.datasource.initial-size=10 //指定启动连接池时,初始建立的连接数量
这也可以实现其目的。
application.properties:
#DataSource
#数据库驱动
jdbc.driver=com.mysql.cj.jdbc.Driver
#数据库链接
jdbc.url=jdbc:mysql://localhost:3306/demo?serverTimezone=GMT
#数据库用户名
jdbc.username=root
#数据库密码
jdbc.password=1214
DataSourceConfiguration.java:
@Configuration //告诉spring容器需要来到这个类下面来检查相关的bean
@MapperScan("com.demo.dao") //配置mybatis mapper的扫描路径
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String jdbcDriver;
@Value("${jdbc.url}")
private String jdbcUrl;
@Value("${jdbc.username}")
private String jdbcUsername;
@Value("${jdbc.password}")
private String jdbcPassword;
@Bean(name = "dataSource")
public ComboPooledDataSource createDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(jdbcDriver);
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setUser(jdbcUsername);
dataSource.setPassword(jdbcPassword);
//关闭连接后不自动commit
dataSource.setAutoCommitOnClose(false);
return dataSource;
}
}
application.properties添加:
#MyBatis
mybatis_config_file=mybatis-config.xml
mapper_path=/mapper/**.xml
entity_package=com.demo.entity
SessionFactoryConfiguration.java:
public class SessionFactoryConfiguration {
//mybatis-config.xml配置文件的路径
@Value("${mybatis_config_file}")
private String mybatisConfigFilePath;
//mybatis mapper文件所在路径
@Value("${mapper_path}")
private String mapperPath;
//实体类所在的package
@Value("${entity_package}")
private String entityPackage;
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;
@Bean(name = "sqlSessionFactory")
public SqlSessionFactoryBean createSqlSessionFactoryBean() throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
//扫描mybatis-config.xml配置文件
sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(mybatisConfigFilePath));
//读取jar文件信息
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//指定mapper文件的扫描路径
String packagSearchPath = PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + mapperPath;//读取路径
sqlSessionFactoryBean.setMapperLocations(resolver.getResources(packagSearchPath));//设置路径
//指定数据源
sqlSessionFactoryBean.setDataSource(dataSource);
//指定映射实体类package的扫描路径
sqlSessionFactoryBean.setTypeAliasesPackage(entityPackage);
return sqlSessionFactoryBean;
}
}
4、dao的创建
AreaDao:
public interface AreaDao {
//列出区域列表
List<Area> queryArea();
//根据Id列出具体区域
Area queryAreaById(int areaId);
//插入区域信息
int insertArea(Area area);
//更新区域信息
int updateArea(Area area);
//删除区域信息
int deleteArea(int areaId);
}
5、mapper的编写
操作数据库的sql语句编写
AreaDao.xml:
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE mapper PUBLIC
"-//mybatis.org//DTD com.example.Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.dao.AreaDao">
<select id="queryArea" resultType="com.demo.entity.Area">
SELECT area_id, area_name,
priority, create_time, last_edit_time
FROM tb_area
ORDER BY priority
DESC
</select>
<select id="queryArea" resultType="com.demo.entity.Area">
SELECT area_id, area_name,
priority, create_time,last_edit_time
FROM tb_area
WHERE
area_id=#{areaId}
</select>
<insert id="insertArea" useGeneratedKeys="true" keyProperty="areaId"
keyColumn="area_id" parameterType="com.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.demo.entity.Area">
update tb_area
<set>
<if test="areaName!=null">area_name=#{areaName},</if>
<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>
6、dao层开发
下面就简单的进行一些单元测试类:
AreaDaoTest.java:
@RunWith(SpringRunner.class)
@SpringBootTest
@FixMethodOrder(MethodSorters.NAME_ASCENDING) // 按方法名大小升序执行
public class AreaDaoTest {
//通过spring容器注入Dao的实现类
@Autowired
private AreaDao areaDao;
@Test
public void testAQueryArea() {
List<Area> areaList = areaDao.queryArea();
// 验证预期值和实际值是否相符
assertEquals(2, areaList.size());
}
@Test
public void testBInsertArea() {
//创建一个区域对象
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 testCQueryAreaById() {
Area area = areaDao.queryAreaById(2);
assertEquals("小可爱", area.getAreaName());
}
@Test
public void testDUpateArea() {
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 testEDeleteArea() {
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());
}
}
可以通过@Ignore来阻碍其一方法的运行,从而进行每一个单元测试
7、service层的实现
services 存放业务得逻辑操作,需要用到事务层来操作数据
/**
* 对标spring-service里面的transactionManager
* 继承TransactionManagementConfigurer是因为开启annotation-driven
*/
@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);
}
}
AreaService接口:
public interface AreaService {
/**
* 获取区域列表
*/
List<Area> getAreaList();
/**
* 通过区域Id获取区域信息
*/
Area getAreaById(int areaId);
/**
* 增加区域信息
*/
boolean addArea(Area area);
/**
* 修改区域信息
*/
boolean modifyArea(Area area);
/**
* 删除区域信息
*/
boolean deleteArea(int areaId);
}
AreaServiceImpl.java:
@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不能为空!");
}
}
}
8、业务controller方法的实现
AreaController.java:
@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 areaStr
* @param request
* @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 areaStr
* @param request
* @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;
}
}
9、统一异常功能的实现
GlobalExceptionHandler.java:
/**
* 统一异常处理类
*/
@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;
}
}
以上便是关于一个微信小程序在后台的简单编写,当然你也可以进行优化,下面我们先进行微信小程序的前端开发ヾ(◍°∇°◍)ノ゙
三、微信小程序的前端入门
可以在微信小程序的文档进行查看相关内容:微信官方文档-小程序(✪ω✪)可先进行下载一个微信开发者工具:微信开发者工具┗( ▔, ▔ )┛
下载点击进入后,微信扫一扫登录后:
具体文件内容的介绍,请移至慕课网的视频进行学习或查阅微信小程序的文档进行学习,下面便开始前端小程序的开发:
选择pages鼠标右键选择新建Page后命名(list),完成后便会生成对应的四个文件
具体的小程序操作就不详细解释了,毕竟我一个后端的,会一些简单的使用了解一下就好,若有兴趣可自行进行学习
其具体源码,请自行观看:
1、list.js
// pages/list/list.js
Page({
/**
* 页面的初始数据
*/
data: {
list: []
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
var that = this;
wx.request({
url: "http://127.0.0.1:8080/superadmin/listarea",
data: {},
method: 'GET',
success: function (res) {
var list = res.data.areaList;
if (list == null) {
var toastText = '获取数据失败' + res.data.errMsg;
wx.showToast({
title: toastText,
icon: '',
duration: 2000
});
} else {
that.setData({
list: list
});
}
}
})
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
},
addArea: function () {
wx.navigateTo({
url: '../operation/operation',
})
},
deleteArea: function (e) {
var that = this;
wx.showModal({
title: '提示',
content: '确定要删除[' + e.target.dataset.areaname + ']吗?',
success: function (sm) {
if (sm.confirm) {
// 用户点击了确定 可以调用删除方法了
wx.request({
url: "http://127.0.0.1:8080/superadmin/removearea",
data: { "areaId": e.target.dataset.areaid },
method: 'GET',
success: function (res) {
var result = res.data.success
var toastText = "删除成功!";
if (result != true) {
toastText = "删除失败" + res.data.errMsg;
} else{
that.data.list.splice(e.target.dataset.index, 1)
//渲染数据
that.setData({
list: that.data.list
});
}
wx.showToast({
title: toastText,
icon: '',
duration: 2000
});
}
})
}
}
})
}
})
2、list.json
{
"navigationBarTitleText": "区域信息列表"
}
3、list.wxml
<!--pages/list/list.wxml-->
<view class="container">
<view class="widget">
<text class="column">ID</text>
<text class="column">区域名</text>
<text class="column">优先级</text>
<text class="link-column">操作</text>
</view>
<scroll-view scroll-y="true">
<view>
<block wx:for="{{list}}">
<view class="widget">
<view>
<text class="column">{{item.areaId}}</text>
<text class="column">{{item.areaName}}</text>
<text class="column">{{item.priority}}</text>
<view class="link-column">
<navigator class="link" url="../operation/operation?areaId={{item.areaId}}">编辑</navigator>|
<text class="link" bindtap="deleteArea" data-areaid="{{item.areaId}}" data-areaname="{{item.areaName}}" data-index="{{index}}">删除</text>
</view>
</view>
</view>
</block>
</view>
</scroll-view>
<button type="primary" bindtap="addArea">添加区域信息</button>
</view>
4、list.wxss
/* pages/list/list.wxss */
.widget {
position: relative;
margin-top: 5rpx;
margin-bottom: 5rpx;
padding-top: 10rpx;
padding-bottom: 10rpx;
padding-left: 40rpx;
padding-right: 40rpx;
border: #ddd 1px solid;
}
.container {
height: 100%;
display: table;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
padding-top: 10rpx;
padding-bottom: 10rpx;
text-align: center;
}
.column {
width: 4rem;
display: table-cell;
}
.link-column {
width: 6rem;
display: table-cell;
}
.link {
color: blue;
display: inline-table;
}