package com.ibatis.io.entity;
public class User {
private Integer id;
private String name;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.ibatis.io.mapper;
import com.ibatis.io.entity.User;
import com.ibatis.io.mybatis.Param;
import com.ibatis.io.mybatis.Select;
import java.util.List;
public interface UserMapper {
@Select("select * from user where name=#{name}")
public List<User> getUser(@Param("name") String name,@Param("age") Integer age);
@Select("select * from user where id=#{id}")
public User getUserById(@Param("id") Integer id);
}
package com.ibatis.io.mybatis;
public class GenericTokenParser {
private final String openToken;
private final String closeToken;
private final TokenHandler handler;
public GenericTokenParser(String openToken, String closeToken, TokenHandler handler) {
this.openToken = openToken;
this.closeToken = closeToken;
this.handler = handler;
}
public String parse(String text) {
if (text == null || text.isEmpty()) {
return "";
}
// search open token
int start = text.indexOf(openToken, 0);
if (start == -1) {
return text;
}
char[] src = text.toCharArray();
int offset = 0;
final StringBuilder builder = new StringBuilder();
StringBuilder expression = null;
while (start > -1) {
if (start > 0 && src[start - 1] == '\\') {
// this open token is escaped. remove the backslash and continue.
builder.append(src, offset, start - offset - 1).append(openToken);
offset = start + openToken.length();
} else {
// found open token. let's search close token.
if (expression == null) {
expression = new StringBuilder();
} else {
expression.setLength(0);
}
builder.append(src, offset, start - offset);
offset = start + openToken.length();
int end = text.indexOf(closeToken, offset);
while (end > -1) {
if (end > offset && src[end - 1] == '\\') {
// this close token is escaped. remove the backslash and continue.
expression.append(src, offset, end - offset - 1).append(closeToken);
offset = end + closeToken.length();
end = text.indexOf(closeToken, offset);
} else {
expression.append(src, offset, end - offset);
offset = end + closeToken.length();
break;
}
}
if (end == -1) {
// close token was not found.
builder.append(src, start, src.length - start);
offset = src.length;
} else {
builder.append(handler.handleToken(expression.toString()));
offset = end + closeToken.length();
}
}
start = text.indexOf(openToken, offset);
}
if (offset < src.length) {
builder.append(src, offset, src.length - offset);
}
return builder.toString();
}
}
package com.ibatis.io.mybatis;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class IntegerTypeHandler implements TypeHandler<Integer> {
@Override
public void setParameter(PreparedStatement statement, int i, Integer value) throws SQLException {
statement.setInt(i, value);
}
@Override
public Integer getResult(ResultSet rs, String columnName) throws SQLException {
return rs.getInt(columnName);
}
}
package com.ibatis.io.mybatis;
import java.lang.reflect.*;
import java.sql.*;
import java.util.*;
public class MapperProxyFactory {
private static final Map<Class<?>, TypeHandler> typeHandlerMap = new HashMap<>();
static {
try {
typeHandlerMap.put(String.class, new StringTypeHandler());
typeHandlerMap.put(Integer.class, new IntegerTypeHandler());
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
public static <T> T getMapper(Class<T> mapper) {
Object proxyInstance = Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{mapper}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取数据库连接
Connection conn = getConnection();
Select annotation = method.getAnnotation(Select.class);
String sql = annotation.value();
Parameter[] parameters = method.getParameters();
HashMap<String, Object> map = new HashMap<>();
for (int i = 0; i < parameters.length; i++) {
String parameter = parameters[i].getAnnotation(Param.class).value();
map.put(parameter, args[i]);
}
// 解析 SQL,并将 #{} 替换为 ?
ParameterMappingTokenHandler tokenHandler = new ParameterMappingTokenHandler();
GenericTokenParser parser = new GenericTokenParser("#{", "}", tokenHandler);
String parse = parser.parse(sql);
// 结果支持List或单个User对象
Object result = null;
// 执行 SQL
List<Object> users;
ResultSetMetaData metaData;
try (PreparedStatement preparedStatement = conn.prepareStatement(parse)) {
List<ParameterMapping> parameterMappings = tokenHandler.getParameterMappings();
for (int i = 0; i < parameterMappings.size(); i++) {
String property = parameterMappings.get(i).getProperty();
Class<?> aClass = map.get(property).getClass();
typeHandlerMap.get(aClass).setParameter(preparedStatement, i + 1, map.get(property));
}
preparedStatement.execute();
Class resultType = null;
Type genericReturnType = method.getGenericReturnType();
if (genericReturnType instanceof Class) {
resultType = (Class) genericReturnType;
} else if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
resultType = (Class) actualTypeArguments[0];
}
users = new ArrayList<>();
metaData = preparedStatement.getMetaData();
List<String> columnList = new ArrayList<>();
for (int i = 0; i < metaData.getColumnCount(); i++) {
columnList.add(metaData.getColumnName(i + 1));
}
HashMap<String, Method> setMap = new HashMap<>();
for (Method declaredMethod : resultType.getDeclaredMethods()) {
if (declaredMethod.getName().startsWith("set")) {
String substring = declaredMethod.getName().substring(3);
substring = substring.substring(0, 1).toLowerCase(Locale.ROOT) + substring.substring(1);
setMap.put(substring, declaredMethod);
}
}
ResultSet resultSet = preparedStatement.getResultSet();
while (resultSet.next()) {
Object instance = resultType.getDeclaredConstructor().newInstance();
for (int i = 0; i < columnList.size(); i++) {
String column = columnList.get(i);
Method setMethod = setMap.get(column);
Class<?> parameterType = setMethod.getParameterTypes()[0];
TypeHandler typeHandler = typeHandlerMap.get(parameterType);
setMethod.invoke(instance, typeHandler.getResult(resultSet, column));
}
users.add(instance);
}
if (method.getReturnType().equals(List.class)) {
result = users;
} else {
result = users.get(0);
}
}
return result;
}
});
return (T) proxyInstance;
}
private static Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC", "root", "123456");
}
}
package com.ibatis.io.mybatis;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Param {
String value();
}
package com.ibatis.io.mybatis;
public class ParameterMapping {
private String property;
public ParameterMapping(String property) {
this.property = property;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
}
package com.ibatis.io.mybatis;
import java.util.ArrayList;
import java.util.List;
public class ParameterMappingTokenHandler implements TokenHandler {
private final List<ParameterMapping> parameterMappings = new ArrayList();
public List<ParameterMapping> getParameterMappings() {
return this.parameterMappings;
}
public String handleToken(String content) {
this.parameterMappings.add(new ParameterMapping(content));
return "?";
}
}
package com.ibatis.io.mybatis;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Created by ggz
* @Date 2023/12/26 14:01
* @Version 1.0.0
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Select {
String value();
}
package com.ibatis.io.mybatis;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @Created by ggz
* @Date 2023/12/26 17:17
* @Version 1.0.0
*/
public class StringTypeHandler implements TypeHandler<String>{
@Override
public void setParameter(PreparedStatement statement, int i, String value) throws SQLException {
statement.setString(i, value);
}
@Override
public String getResult(ResultSet rs, String columnName) throws SQLException {
return rs.getString(columnName);
}
}
package com.ibatis.io.mybatis;
public interface TokenHandler {
String handleToken(String content);
}
package com.ibatis.io.mybatis;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @Created by ggz
* @Date 2023/12/26 17:15
* @Version 1.0.0
*/
public interface TypeHandler<T> {
void setParameter(PreparedStatement statement, int i, T value) throws SQLException;
T getResult(ResultSet rs, String columnName) throws SQLException;
}
package com.ibatis.io;
import com.ibatis.io.entity.User;
import com.ibatis.io.mapper.UserMapper;
import com.ibatis.io.mybatis.MapperProxyFactory;
import java.util.List;
/**
* @Created by ggz
* @Date 2023/12/26 14:24
* @Version 1.0.0
*/
public class App {
public static void main(String[] args) {
UserMapper mapper = MapperProxyFactory.getMapper(UserMapper.class);
List<User> users = mapper.getUser("小米",20);
System.out.println(users);
User userById = mapper.getUserById(2);
System.out.println(userById);
}
}
/*标签:java,String,实现,简易,offset,mybatis,import,com,public From: https://www.cnblogs.com/goPush/p/17930634.html
Navicat Premium Data Transfer
Source Server : local
Source Server Type : MySQL
Source Server Version : 80027
Source Host : localhost:3306
Source Schema : test
Target Server Type : MySQL
Target Server Version : 80027
File Encoding : 65001
Date: 27/12/2023 15:14:42
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint(0) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`age` int(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '小米', 20);
INSERT INTO `user` VALUES (2, '大米', 22);
SET FOREIGN_KEY_CHECKS = 1;