尝试做一个springboot的框架demo,不足之处,请留言指出,不胜感谢。
篇幅比较长,可以通过目录来找到需要的部分代码。
以下是我的开发环境,仅做参考
先做一个简单的增删改查,使用mybatis框架。之前写过注解版的《Mybatis 简单应用》,这里用的是xml配置版。
CREATE TABLE `db_laowu`.`Order` (
`OrderId` INT NOT NULL AUTO_INCREMENT,
`Code` VARCHAR(45) NOT NULL,
`Name` VARCHAR(45) NOT NULL,
`CreateTime` VARCHAR(45) NOT NULL,
`LeftAmount` VARCHAR(45) NOT NULL,
PRIMARY KEY (`OrderId`));
CREATE TABLE `db_laowu`.`OrderDetail` (
`OrderDetailId` INT NOT NULL AUTO_INCREMENT,
`OrderId` INT NOT NULL,
`ProductId` INT NOT NULL,
`ProductCount` INT NOT NULL,
PRIMARY KEY (`OrderDetailId`));
我是用vscode创建的,通过命令行:
依赖初步选择了以下,有缺的后面再加:
使用vscode的话,现在可以先分一下层,建一下文件夹,大致如下:
application.properties改为application.yml
spring:
application:
name: springboot-study-demo
profiles:
active: dev
server:
port: 1111
servlet:
context-path: /springboot-study-demo
新增application-dev.yml,包含一些环境特有的信息,这里存放下数据库链接
itlaowu:
datasource:
type: mysql
//由于是容器内的mysql,这里用端口33060
jdbc-url: jdbc:mysql://localhost:33060/db_laowu?useUnicode=true&characterEncoding=UTF-8
username: it_laowu
password: "!Aa123456"
driver-class-name: com.mysql.jdbc.Driver
core/base下,我们存放一些基类。
package com.it_laowu.springbootstudy.springbootstudydemo.core.base;
import lombok.Data;
/**
* 查询条件基类 不能直接指定sortSql,而是要校验安全性,再拼接sortType sortFields
*/
@Data
public abstract class BaseCondition {
private String sortType;
private String sortFields;
private String sortSql;
private int pageSize;
private int currPageIndex;
public String getSortSql() {
if (sortFields != null && !sortFields.equals("") && !sortFields.equals("null")) {
if ("asc,desc".indexOf(sortType.toLowerCase()) == -1) {
return "";
}
final Class<?> childClass = getChildClass();
for (String field : sortFields.split(",")) {
try {
// 这里可以根据字段名,找到数据库对应的列名。本例简单认为两者相等。
childClass.getDeclaredField(field);
} catch (NoSuchFieldException | SecurityException e) {
return "";
}
}
return String.format(" ORDER BY %s %s ", sortFields, sortType);
} else {
return "";
}
}
abstract public Class<?> getChildClass();
}
package com.it_laowu.springbootstudy.springbootstudydemo.core.base;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface IBaseDao<Bean,Condition> {
//全部查询,可以加入分页
public List<Bean> findAll(@Param("conditionQC") Condition conditionQC);
//该方法不对外,容易出错
Bean findOne(@Param("keyId") int keyId);
public int insert(Bean entity);
public int update(Bean entity);
public int delete(@Param("keyId") int keyId);
}
package com.it_laowu.springbootstudy.springbootstudydemo.core.base;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface IBaseService<Bean,Condition> {
//内部方法
IBaseDao<Bean,Condition> getBaseDao();
default List<Bean> findAll(@Param("conditionQC") Condition condition){
return getBaseDao().findAll(condition);
}
//内部方法
default Bean findOne(@Param("keyId") int keyId){
return getBaseDao().findOne(keyId);
}
default int insert(Bean entity){
return getBaseDao().insert(entity);
}
default int update(Bean entity){
return getBaseDao().update(entity);
}
default int delete(@Param("keyId") int keyId){
return getBaseDao().delete(keyId);
}
}
package com.it_laowu.springbootstudy.springbootstudydemo.core.base;
import lombok.Data;
@Data
public class ResultBody {
private String code;
private String message;
private String detailMessage;
public ResultBody() {
}
public ResultBody(String code, String message) {
this.code = code;
this.message = message;
}
public ResultBody(String code, String message, String detailMessage) {
this.code = code;
this.message = message;
this.detailMessage = detailMessage;
}
}
上面是基类,接下来实现Order表的相关类。
package com.it_laowu.springbootstudy.springbootstudydemo.bean.condition;
import java.math.BigDecimal;
import java.sql.Timestamp;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.core.base.BaseCondition;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class OrderCondition extends BaseCondition {
private int orderId;
private String code;
private String name;
private Timestamp createTime;
private BigDecimal leftAmount;
@Override
public Class<?> getChildClass() {
return OrderBean.class;
}
}
package com.it_laowu.springbootstudy.springbootstudydemo.bean;
import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Timestamp;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@SuppressWarnings("serial")
public class OrderBean implements Serializable{
@NotNull
private int orderId;
@NotNull
@Size(min = 5, max = 12,message = "长度在5-12")
private String code;
@NotNull
private String name;
@NotNull
private Timestamp createTime;
@Min(value=0,message="必须大于0")
private BigDecimal leftAmount;
}
package com.it_laowu.springbootstudy.springbootstudydemo.dao;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.condition.OrderCondition;
import com.it_laowu.springbootstudy.springbootstudydemo.core.base.IBaseDao;
public interface OrderDao extends IBaseDao<OrderBean,OrderCondition> {
}
package com.it_laowu.springbootstudy.springbootstudydemo.service;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.condition.OrderCondition;
import com.it_laowu.springbootstudy.springbootstudydemo.core.base.IBaseService;
public interface IOrderService extends IBaseService<OrderBean,OrderCondition> {
}
package com.it_laowu.springbootstudy.springbootstudydemo.service.impl;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.condition.OrderCondition;
import com.it_laowu.springbootstudy.springbootstudydemo.core.base.IBaseDao;
import com.it_laowu.springbootstudy.springbootstudydemo.dao.OrderDao;
import com.it_laowu.springbootstudy.springbootstudydemo.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class OrderServiceImpl implements IOrderService {
@Autowired
public OrderDao orderDao;
@Override
public IBaseDao<OrderBean, OrderCondition> getBaseDao() {
return orderDao;
}
}
mybatisMappers
,写下mybatis.xml
<mapper namespace="com.it_laowu.springbootstudy.springbootstudydemo.dao.OrderDao">
<resultMap id="orderResultMap" type="com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean">
<result column="orderId" property="orderId"/>
<result column="code" property="code"/>
<result column="name" property="name"/>
<result column="createTime" property="createTime"/>
<result column="leftAmount" property="leftAmount"/>
resultMap>
<select id="findAll" resultMap="orderResultMap">
select orderId,code,`name`,createTime,leftAmount
from `Order`
<where>
<if test="conditionQC.orderId != 0">
and orderId = #{conditionQC.orderId}
if>
<if test="conditionQC.code != null and '' != conditionQC.code">
and code like concat('%',#{conditionQC.code},'%')
if>
<if test="conditionQC.name != null and '' != conditionQC.name">
and name like concat('%',#{conditionQC.name},'%')
if>
<if test="conditionQC.createTime != null and '' != conditionQC.createTime">
and createTime like concat('%',#{conditionQC.createTime},'%')
if>
<if test="conditionQC.leftAmount != null and '' != conditionQC.leftAmount">
and leftAmount like concat('%',#{conditionQC.leftAmount},'%')
if>
where>
<choose>
<when test="conditionQC.sortSql == null">
order by orderId
when>
<otherwise>
${conditionQC.sortSql}
otherwise>
choose>
select>
<select id="findOne" resultMap="orderResultMap">
select orderId,code,`name`,createTime,leftAmount
from `Order`
where orderId = #{keyId}
select>
<insert id="insert" parameterType="com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean">
insert into `Order`(orderId,`code`,`name`,createTime,leftAmount)
values(#{orderId},#{code},#{name},#{createTime},#{leftAmount})
insert>
<update id="update" parameterType="com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean">
update `Order`
<set>
<if test="code!=null"> `code`=#{code}, if>
<if test="name!=null"> `name`=#{name}, if>
<if test="createTime!=null"> createTime=#{createTime}, if>
<if test="leftAmount!=null"> leftAmount=#{leftAmount}, if>
set>
where orderId = #{orderId}
update>
<delete id="delete" parameterType="int">
delete from `Order` where orderId = #{keyId}
delete>
mapper>
package com.it_laowu.springbootstudy.springbootstudydemo.controller;
import java.util.List;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.OrderBean;
import com.it_laowu.springbootstudy.springbootstudydemo.bean.condition.OrderCondition;
import com.it_laowu.springbootstudy.springbootstudydemo.service.IOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PathVariable;
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;
@RestController
@RequestMapping(value = "/order")
public class OrderController {
@Autowired
public IOrderService orderService;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String hello() {
return "hello world:";
}
@RequestMapping(value = "/list", method = RequestMethod.GET)
public List<OrderBean> orders(OrderCondition orderCondition) {
return orderService.findAll(orderCondition);
}
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public OrderBean order(@PathVariable(value = "id") int id) {
return orderService.findOne(id);
}
//新增时数据校验
@RequestMapping(value = "/add", method = RequestMethod.POST)
public int add(@Validated @RequestBody OrderBean orderBean) {
return orderService.insert(orderBean);
}
//修改时不校验数据,当然高级一点会指定要更新哪些字段,然后同样校验数据
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public int update(@PathVariable(value = "id") int id, @RequestBody OrderBean orderBean) {
return orderService.update(orderBean.setOrderId(id));
}
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public int delete(@PathVariable(value = "id") int id) {
return orderService.delete(id);
}
}
package com.it_laowu.springbootstudy.springbootstudydemo.core.Config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(AppConfig.COMPONENTSCAN)
@MapperScan(basePackages = AppConfig.MAPPERSCAN)
public class AppConfig {
protected static final String COMPONENTSCAN="com.it_laowu";
protected static final String MAPPERSCAN="com.it_laowu.**.dao";
protected static final String MAPPERPATH="classpath*:mybatisMappers/**/*.mybatis.xml";
public AppConfig(){
System.out.println("AppConfig start");
}
}
package com.it_laowu.springbootstudy.springbootstudydemo.core.Config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.session.LocalCacheScope;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
@Configuration
@ConditionalOnClass(DataSource.class)
@AutoConfigureAfter(AppConfig.class)
public class DataSourceConfig {
public DataSourceConfig(){
System.out.println("DataSourceConfig start");
}
//从application-dve中读取数据库配置
@Autowired
private DSConfigProperties dSConfigProperties;
@Bean(name="mybatisDataSource")
@Primary
@ConfigurationProperties(prefix="itlaowu.datasource")
public DataSource dataSource() throws Exception {
return DataSourceBuilder.create().build();
}
@Bean(name = "mybatisSqlSessionFactory")
@Primary
@DependsOn(value = "springContextUtil")
public SqlSessionFactory sqlSessionFactory(@Qualifier("mybatisDataSource") DataSource dataSource) throws Exception {
final SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// mybatis.xml路径
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(AppConfig.MAPPERPATH));
// 配置mybatis config
bean.setConfiguration(createMybatisConfig());
// 配置数据库
bean.setDatabaseIdProvider(new DatabaseIdProvider() {
@Override
public String getDatabaseId(final DataSource dataSource) throws SQLException {
return dSConfigProperties.getType();
}
});
return bean.getObject();
}
// mybatis配置
private org.apache.ibatis.session.Configuration createMybatisConfig() {
final org.apache.ibatis.session.Configuration config = new org.apache.ibatis.session.Configuration();
config.setCacheEnabled(true);
config.setLazyLoadingEnabled(true);
config.setLogPrefix("dao.");
config.setLocalCacheScope(LocalCacheScope.SESSION);
return config;
}
@Bean(name = "mybatisSqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("mybatisSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
@Bean(name = "mybatisTransactionManager")
public DataSourceTransactionManager mybatisMasterTransactionManager(@Qualifier("mybatisDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
package com.it_laowu.springbootstudy.springbootstudydemo.core.Config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Data;
@Component
@ConfigurationProperties(prefix="itlaowu.datasource")
@Data
public class DSConfigProperties {
private String type;
private String jdbcUrl;
private String username;
private String password;
private String driverClassName;
}