作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
最核心的内容前两篇已经讲完了,这一篇只有代码:
先看demo目录下的三个文件:
DemoApplication.java
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);
}
}
User.java
package com.example.demo;
import com.example.demo.mybatisplus.annotations.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author mx
*/
@Data
@TableName("t_user")
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private Date birthday;
}
UserMapper.java
package com.example.demo;
import com.example.demo.mybatisplus.AbstractBaseMapper;
/**
* @author mx
*/
public class UserMapper extends AbstractBaseMapper {
}
mybatisplus下AbstractBaseMapper.java
package com.example.demo.mybatisplus;
import com.example.demo.mybatisplus.annotations.TableName;
import com.example.demo.mybatisplus.core.JdbcTemplate;
import com.example.demo.mybatisplus.query.QueryWrapper;
import com.example.demo.mybatisplus.query.SqlParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Mapper基类
*
* @author mx
*/
public abstract class AbstractBaseMapper {
private static Logger logger = LoggerFactory.getLogger(AbstractBaseMapper.class);
private JdbcTemplate jdbcTemplate = new JdbcTemplate();
private Class beanClass;
private final String TABLE_NAME;
private static final String DEFAULT_LOGICAL_TYPE = " and ";
public AbstractBaseMapper() {
// DO对象的Class
beanClass = (Class) ((ParameterizedType) this.getClass()
.getGenericSuperclass())
.getActualTypeArguments()[0];
// DO对应的表名 TODO 非空判断及默认处理
TABLE_NAME = beanClass.getAnnotation(TableName.class).value();
}
public T select(QueryWrapper queryWrapper) {
List list = this.list(queryWrapper);
if (!list.isEmpty()) {
return list.get(0);
}
return null;
}
public List list(QueryWrapper queryWrapper) {
StringBuilder sqlBuilder = new StringBuilder("SELECT * FROM ").append(TABLE_NAME).append(" WHERE ");
List
annotations下的TableName.java
package com.example.demo.mybatisplus.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author mx
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableName {
String value();
}
core下的
JdbcTemplate.java
package com.example.demo.mybatisplus.core;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* JdbcTemplate,简化jdbc操作
*
* @author mx
*/
public class JdbcTemplate {
public List queryForList(String sql, List params, RowMapper rowMapper) throws SQLException {
return query(sql, params, rowMapper);
}
public T queryForObject(String sql, List params, RowMapper rowMapper) throws SQLException {
List result = query(sql, params, rowMapper);
return result.isEmpty() ? null : result.get(0);
}
public List queryForList(String sql, List params, Class clazz) throws Exception {
return query(sql, params, clazz);
}
public T queryForObject(String sql, List params, Class clazz) throws Exception {
List result = query(sql, params, clazz);
return result.isEmpty() ? null : result.get(0);
}
public int update(String sql, List params) throws SQLException {
// 1.获取Connection
Connection conn = getConnection();
// 2.传入sql模板、sql参数,得到PreparedStatement
PreparedStatement ps = getPreparedStatement(sql, params, conn);
// 3.执行更新(增删改)
int affectedRows = ps.executeUpdate();
// 4.释放资源
closeConnection(conn, ps, null);
return affectedRows;
}
// ************************* private methods **************************
private List query(String sql, List params, RowMapper rowMapper) throws SQLException {
// 外部传入rowMapper(手写规则)
return baseQuery(sql, params, rowMapper);
}
private List query(String sql, List params, Class clazz) throws Exception {
// 自己创建rowMapper(反射)后传入
BeanHandler beanHandler = new BeanHandler<>(clazz);
return baseQuery(sql, params, beanHandler);
}
/**
* 基础查询方法,必须传入Bean的映射规则
*
* @param sql
* @param params
* @param rowMapper
* @return
* @throws SQLException
*/
private List baseQuery(String sql, List params, RowMapper rowMapper) throws SQLException {
// TODO 参数非空校验
// 1.获取Connection
Connection conn = getConnection();
// 2.传入sql模板、sql参数,得到PreparedStatement
PreparedStatement ps = getPreparedStatement(sql, params, conn);
// 3.执行查询
ResultSet rs = ps.executeQuery();
// 4.处理结果
List result = new ArrayList<>();
while (rs.next()) {
T obj = rowMapper.mapRow(rs);
result.add(obj);
}
// 5.释放资源
closeConnection(conn, ps, rs);
return result;
}
/**
* 内部类,实现了RowMapper接口,底层使用反射
*
* @param
*/
private static class BeanHandler implements RowMapper {
// clazz表示最终封装的bean类型
private Class clazz;
public BeanHandler(Class clazz) {
this.clazz = clazz;
}
@Override
public R mapRow(ResultSet rs) {
try {
if (rs.next()) {
// 1.获取表数据
ResultSetMetaData metaData = rs.getMetaData();
// 2.反射创建bean
R bean = clazz.newInstance();
// 3.利用反射,把表数据设置到bean中
for (int i = 0; i < metaData.getColumnCount(); i++) {
String name = metaData.getColumnName(i + 1);
Object value = rs.getObject(name);
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
field.set(bean, value);
}
// 4.返回bean
return bean;
} else {
return null;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private PreparedStatement getPreparedStatement(String sql, List params, Connection conn) throws SQLException {
// 1.传入sql模板,得到PreparedStatement
PreparedStatement ps = conn.prepareStatement(sql);
// 2.为sql模板设置参数
for (int i = 0; i < params.size(); i++) {
ps.setObject(i + 1, params.get(i));
}
return ps;
}
private Connection getConnection() throws SQLException {
// TODO 可以抽取配置到properties文件
String url = "jdbc:mysql://localhost:3306/demo";
String user = "root";
String password = "123456";
return DriverManager.getConnection(url, user, password);
}
private void closeConnection(Connection conn, PreparedStatement preparedStatement, ResultSet rs) throws SQLException {
if (rs != null) {
rs.close();
}
if (preparedStatement != null) {
preparedStatement.close();
}
if (conn != null) {
conn.close();
}
}
}
RowMapper.java
package com.example.demo.mybatisplus.core;
import java.sql.ResultSet;
/**
* 结果集映射器
*
* @author mx
*/
@FunctionalInterface
public interface RowMapper {
/**
* 将结果集转为指定的Bean
*
* @param resultSet
* @return
*/
T mapRow(ResultSet resultSet);
}
query下的
QueryWrapper.java
package com.example.demo.mybatisplus.query;
import com.example.demo.mybatisplus.utils.ConditionFunction;
import com.example.demo.mybatisplus.utils.Reflections;
import java.util.HashMap;
import java.util.Map;
/**
* 模拟MyBatis-Plus的LambdaQueryWrapper(思路完全不同,仅仅是形似)
*
* @author mx
*/
public class QueryWrapper {
// conditionMap,收集查询条件
// {
// " LIKE ": {
// "name": "bravo1988"
// },
// " = ": {
// "age": 18
// }
// }
private final Map conditionMap = new HashMap<>();
// 操作符类型,比如 name like 'bravo' 中的 LIKE
private static final String OPERATOR_EQ = " = ";
private static final String OPERATOR_GT = " > ";
private static final String OPERATOR_LT = " < ";
private static final String OPERATOR_LIKE = " LIKE ";
public QueryWrapper eq(ConditionFunction fn, Object value) {
String columnName = Reflections.fnToColumnName(fn);
conditionMap.put(OPERATOR_EQ, new SqlParam(columnName, value));
return this;
}
public QueryWrapper gt(ConditionFunction fn, Object value) {
String columnName = Reflections.fnToColumnName(fn);
conditionMap.put(OPERATOR_GT, new SqlParam(columnName, value));
return this;
}
public QueryWrapper lt(ConditionFunction fn, Object value) {
String columnName = Reflections.fnToColumnName(fn);
conditionMap.put(OPERATOR_LT, new SqlParam(columnName, value));
return this;
}
public QueryWrapper like(ConditionFunction fn, Object value) {
String columnName = Reflections.fnToColumnName(fn);
conditionMap.put(OPERATOR_LIKE, new SqlParam(columnName, "%" + value + "%"));
return this;
}
public Map build() {
return conditionMap;
}
}
SqlParam.java
package com.example.demo.mybatisplus.query;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author mx
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SqlParam {
private String columnName;
private Object value;
}
utils下的
ConditionFunction.java
package com.example.demo.mybatisplus.utils;
import java.io.Serializable;
import java.util.function.Function;
/**
* 扩展java.util.function包下的Function接口:支持Serializable
* 搭配Reflections工具类一起使用,用于获取Lambda表达式的方法名
*
* @author mx
*/
@FunctionalInterface
public interface ConditionFunction extends Function, Serializable {
}
Reflections.java
package com.example.demo.mybatisplus.utils;
import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.regex.Pattern;
/**
* 获取Lambda入参的方法名
*
* @author mx
*/
public class Reflections {
private static final Pattern GET_PATTERN = Pattern.compile("^get[A-Z].*");
private static final Pattern IS_PATTERN = Pattern.compile("^is[A-Z].*");
/**
* 注意: 非标准变量(非小驼峰)调用这个方法可能会有问题
*
* @param fn
* @param
* @return
*/
public static String fnToColumnName(ConditionFunction fn) {
try {
Method method = fn.getClass().getDeclaredMethod("writeReplace");
method.setAccessible(Boolean.TRUE);
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
String getter = serializedLambda.getImplMethodName();
// 对于非标准变量生成的Get方法这里可以直接抛出异常,或者打印异常日志
if (GET_PATTERN.matcher(getter).matches()) {
getter = getter.substring(3);
} else if (IS_PATTERN.matcher(getter).matches()) {
getter = getter.substring(2);
}
return Introspector.decapitalize(getter);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
}
其实第一篇的内容是最难的,不只是从0到1,而是从0到90,后面两篇其实只是90到100,在这基础稍微扩展了一下而已。
AbstractBaseMapper代码还有冗余,有兴趣的同学可以自行完善。但还是那句话,如果你的目的是为了锻炼封装能力,可以精益求精,但我们的AbstractBaseMapper注定不能用于生产,即使要优化,点到为止即可。
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
阶段4、深入jdk其余源码解析
阶段5、深入jvm源码解析