use of com.github.dreamroute.mybatis.pro.core.exception.MyBatisProException in project mybatis-pro by Dreamroute.
the class MyBatisProUtil method processSpecialMethods.
public static Set<Resource> processSpecialMethods(Set<Resource> resources) {
return resources.stream().map(resource -> {
Class<?> mapperCls = getNamespaceFromXmlResource(resource);
validateDuplicateMethods(mapperCls, resource);
Document doc = createDocumentFromResource(resource);
List<String> specialMethods = getSpecialMethods(mapperCls);
if (!isEmpty(specialMethods)) {
Class<?> entityCls = getTypeArgument(mapperCls);
if (!hasAnnotation(entityCls, Table.class)) {
throw new MyBatisProException("实体" + entityCls.getName() + "必须包含@" + Table.class.getName() + "注解");
}
// 将findBy方法的返回值的别名进行缓存,这里将缓存里面没有的返回值进行缓存,实体部分已经在前面进行了缓存,这里缓存非实体返回类型
Map<String, String> name2Type = getMethodName2ReturnType(mapperCls);
cacheAlias(name2Type);
specialMethods.forEach(specialMethodName -> {
String conditions = null;
String sql = null;
MapperLabel mapperLabel = SELECT;
if (specialMethodName.startsWith("findBy")) {
conditions = specialMethodName.substring(6);
sql = "select * from ";
} else if (specialMethodName.startsWith("deleteBy")) {
conditions = specialMethodName.substring(8);
sql = "delete from ";
mapperLabel = DELETE;
} else if (specialMethodName.startsWith("countBy")) {
conditions = specialMethodName.substring(7);
sql = "select count(*) c from ";
} else if (specialMethodName.startsWith("existBy")) {
conditions = specialMethodName.substring(7);
sql = "select (case when count(*)=0 then 'false' ELSE 'true' end) from ";
}
sql += getAnnotationValue(entityCls, Table.class) + " <where> " + createCondition(conditions, FIELDS_ALIAS_CACHE.get(entityCls));
// 对于delete需要特殊处理,delete不需要设置resultType
String resultType = mapperLabel == DELETE ? null : name2Type.get(specialMethodName);
fillSqlNode(doc, mapperLabel, specialMethodName, resultType, sql, null, null);
});
}
return createResourceFromDocument(doc);
}).collect(toSet());
}
use of com.github.dreamroute.mybatis.pro.core.exception.MyBatisProException in project mybatis-pro by Dreamroute.
the class MyBatisProUtil method getNamespaceFromXmlResource.
/**
* 从mapper.xml文件中获取namespace
*
* @param resource mapper.xml数据流
*/
public static Class<?> getNamespaceFromXmlResource(Resource resource) {
try {
XPathParser xPathParser = new XPathParser(resource.getInputStream(), true, null, new XMLMapperEntityResolver());
XNode mapperNode = xPathParser.evalNode(MAPPER.getCode());
String namespace = mapperNode.getStringAttribute(NAMESPACE.getCode());
return loadClass(namespace);
} catch (Exception e) {
throw new MyBatisProException("解析mapper.xml文件获取namespace出错", e);
}
}
use of com.github.dreamroute.mybatis.pro.core.exception.MyBatisProException in project mybatis-pro by Dreamroute.
the class DocumentUtil method createDocumentFromResource.
/**
* 将Resource转换成Document
*/
public static Document createDocumentFromResource(Resource resource) {
try {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
documentBuilderFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
documentBuilderFactory.setValidating(false);
documentBuilderFactory.setNamespaceAware(false);
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
// 此处需要设置EntityResolver,以便从classpath寻找dtd文件进行解析,否则会从网路下载,很慢并且可能会connect timeout
builder.setEntityResolver(new XMLMapperEntityResolver());
return builder.parse(resource.getInputStream());
} catch (Exception e) {
throw new MyBatisProException("创建Document失败", e);
}
}
use of com.github.dreamroute.mybatis.pro.core.exception.MyBatisProException in project mybatis-pro by Dreamroute.
the class MyBatisProUtil method validateDuplicateMethods.
/**
* 校验Mapper接口内的xxxBy方法不能与xml文件的方法有同名
*/
private static void validateDuplicateMethods(Class<?> mapperCls, Resource resource) {
XPathParser xPathParser;
try {
xPathParser = new XPathParser(resource.getInputStream(), true, null, new XMLMapperEntityResolver());
} catch (Exception e) {
throw new MyBatisProException("解析" + mapperCls.getName() + "对应的mapper.xml文件失败!");
}
List<XNode> selectMethods = xPathParser.evalNodes("mapper/select");
List<XNode> insertMethods = xPathParser.evalNodes("mapper/insert");
List<XNode> updateMethods = xPathParser.evalNodes("mapper/update");
List<XNode> deleteMethods = xPathParser.evalNodes("mapper/delete");
List<XNode> methods = new ArrayList<>();
methods.addAll(selectMethods);
methods.addAll(insertMethods);
methods.addAll(updateMethods);
methods.addAll(deleteMethods);
Set<String> xmlMethodNames = methods.stream().map(node -> node.getStringAttribute(ID.getCode())).collect(toSet());
// BaseMapper的方法 + xxxBy方法
Set<String> innerMethodNames = getBaseMethodNames();
List<String> specialMethods = getSpecialMethods(mapperCls);
innerMethodNames.addAll(specialMethods);
SetView<String> intersection = Sets.intersection(xmlMethodNames, innerMethodNames);
if (!isEmpty(intersection)) {
throw new MyBatisProException("不允许接口" + mapperCls.getName() + "的方法" + toJsonStr(innerMethodNames) + "与" + resource.getFilename() + "文件中的方法重名");
}
}
use of com.github.dreamroute.mybatis.pro.core.exception.MyBatisProException in project mybatis-pro by Dreamroute.
the class DocumentUtil method createResourceFromDocument.
/**
* 将Document转换成Resource
*/
public static Resource createResourceFromDocument(Document document) {
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, document.getDoctype().getPublicId());
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, document.getDoctype().getSystemId());
transformer.setOutputProperty("encoding", "UTF-8");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transformer.transform(new DOMSource(document), new StreamResult(bos));
String xml = bos.toString("UTF-8");
// 必须要将尖括号进行替换,否则要报错
String replace = xml.replace(">", ">").replace("<", "<");
NamedNodeMap attributes = document.getElementsByTagName(MAPPER.getCode()).item(0).getAttributes();
String namespace = attributes.item(0).getTextContent();
// 而mybatis-pro插件生成的resource都是byteArrayResource,如果不带desc,那么所有的resource的toString就都相同,反之带上desc的toString方法就能区分
return new ByteArrayResource(replace.getBytes(StandardCharsets.UTF_8), namespace);
} catch (Exception e) {
throw new MyBatisProException("Document转成Resource失败", e);
}
}
Aggregations