-
Notifications
You must be signed in to change notification settings - Fork 27
services.sql 和 Servie类 命名对应不上写的很痛苦 #22
Comments
主要问题是开发体验感觉不太好 吊打dubbo+nacos。目前感觉没有spring colud+nacos好用(可能是还不太熟悉) leanlone 只需要写 services.sql + service |
lealone 一定要先写 services.sql,写完了执行一下,如果对应的 Service 类不存在会自动创建。 -- 创建服务: hello_service
create service if not exists hello_service (
say_hello(name varchar) varchar -- HelloService 方法定义
)
implement by 'org.lealone.examples.rpc.HelloService' -- HelloService 默认实现类,不存在会自动创建 或者这样写 sql -- 创建服务: user_service,会生成一个对应的UserService接口
create service if not exists user_service (
add_user(name varchar, age int) long, -- 定义UserService接口方法 add_user
find_by_name(name varchar) user -- 定义UserService接口方法 find_by_name
)
package 'org.lealone.examples.fullstack.generated.service' -- UserService接口所在的包名
implement by 'org.lealone.examples.fullstack.UserServiceImpl' -- UserService接口的默认实现类
generate code './src/main/java' -- UserService接口源文件的根目录 会生成一个 UserService 接口,你不用维护这个接口的,每次修改 services.sql 执行一下,都会生成新的 UserService 接口, 这种方式调用方不但可以通过 url 调用服务,还可以直接通过 UserService 接口调,性能也更好。 |
易用性还可以有进一步的改进空间,比如不用在 create service 中敲服务的方法名了,自动通过反射现有的 java 类就可以了 -- 创建服务: hello_service
create service if not exists hello_service
implement by 'org.lealone.examples.rpc.HelloService' -- 自动通过反射 HelloService 类查找它的可用 public 方法。 前题是通过反射要能拿到方法参数名,编译后的 class 文件不能把参数名信息去掉。 |
返回值只能是string,基础类型加model吗,list可以吗 |
支持的类型在这里 |
不在 create service 中敲服务的方法名的话最后发现还不如用注解更方便。 drop service if exists node_controller;
create service if not exists node_controller (
get(id long) node,
find_by_instance_id(instance_id long) varchar,
delete_by_instance_id(instance_id long) void
)
implement by 'com.eesstudio.service.NodeController';
@RequiredArgsConstructor
public class NodeController {
final NodeService nodeService;
public String get(long id) {
return nodeService.get(id).encode();
}
public String findByInstanceId(long instanceId) {
return new JsonArray(nodeService.findByInstanceId(instanceId)).encode();
}
public void deleteByInstanceId(long instanceId) {
nodeService.deleteByInstanceId(instanceId);
}
}
public class NodeService {
public Node get(long id) {
return Node.dao.where().id.eq(id).findOne();
}
public List<Node> findByInstanceId(long instanceId) {
return Node.dao.where().instanceId.eq(instanceId).orderBy().sort.desc().findList();
}
public void deleteByInstanceId(long instanceId) {
Node.dao.where().instanceId.eq(instanceId).delete();
}
}
|
用 javac 编译类或者在 eclipse 中编译类,默认都是没丢掉参数名的,你那个 Node 又是个 model 类, drop service if exists node_Service;
create service if not exists node_Service
implement by 'com.eesstudio.service.NodeService';
public class NodeService {
public Node get(long id) {
return Node.dao.where().id.eq(id).findOne();
}
public List<Node> findByInstanceId(long instanceId) {
return Node.dao.where().instanceId.eq(instanceId).orderBy().sort.desc().findList();
}
public void deleteByInstanceId(long instanceId) {
Node.dao.where().instanceId.eq(instanceId).delete();
}
} |
不配置方法会提示 java.lang.RuntimeException: no method: GET |
用现有的方案写你那个例子可以这么写 drop service if exists node_service;
create service if not exists node_service(
get(id long) node,
find_by_instance_id(instance_id long) array,
delete_by_instance_id(instance_id long) void
)
implement by 'com.eesstudio.service.NodeService'; 执行上面的 sql 后默认帮你创建的类是: public class NodeService {
public Node get(long id) {
return null;
}
public Array findByInstanceId(long instanceId) {
return null;
}
public void deleteByInstanceId(long instanceId) {
}
} 然后你在里面填代码就好了,不用自己转 String。 |
还没有实现,只是说可以这么实现,但是这样做的话,别人就不知道怎么调用你的服务了,create service 其实就是给调用者提供一个接口规范,当然要根据你的 java 类反向生成完整的 create service 语句也是可以的,只是多了一些体力活而已。 |
services.sql 相当于一个接口规范+接口文档。 |
复杂类型你可以通过 create table xxx 创建,我们的项目一般都是把 create table xxx 和 create service yyy 全丢给调用方,然后他们通过 /service/yyy/method?p=v 这种标准格式调用就好了。 |
后续再看看怎么支持 |
是的,但是没有太难以接受了。 sql.Array 这个对象连 forEach 都没有,如果需要二次处理,要调用getResultSet(这个方法还抛SqlException)然后是一堆,字符串字段获取数据非常不利用重构。 |
java.sql.Array 设计得确实很糟糕,你只能 (Object[]) getArray() |
static ManualInStockService create() {
return create(null);
}
static ManualInStockService create(String url) {
if (url == null)
url = ClientServiceProxy.getUrl();
if (ClientServiceProxy.isEmbedded(url))
return new com.eesstudio.wms.admin.service.ManualInStockServiceImpl();
else
return new ServiceProxy(url);
}
自动生成的 service 建议这里面的create改一个用户用不到的方法,防止冲突。 |
这个已经有考虑到了,后续提供一个参数在 create service 语句中加上 parameters(create_method_name='xxx') 就可以生成别的名字了。 |
@qqcbqqkcel 代码已经提交,可以在 create service 语句最后加上 parameters(create_method_name='_create') 或别的名字。 |
set @packageName 'org.lealone.examples.hello.service.generated'; -- 生成的服务接口所在的包名
drop service if exists user_service;
create service if not exists user_service (
create(user user) void,
update(user user) void,
delete(id long) void,
get(id long) user
)
parameters(create_method_name='createService')
package @packageName
implement by 'org.lealone.examples.hello.service.UserServiceImpl' -- HelloService 接口的默认实现类
generate code @srcDir;
drop service if exists user_security_service;
create service if not exists user_security_service (
get_user_security_by_user_id(user_id long) user_security,
delete_user_security_by_user_id(user_id long) void,
)
parameters(create_method_name='createService')
package @packageName
implement by 'org.lealone.examples.hello.service.UserSecurityServiceImpl' -- HelloService 接口的默认实现类
generate code @srcDir;
这个下划线有配置参数吗(直接sql是啥代码里面就是啥不进行转换) |
目前没有,因为 sql 的标识符直接转成 java 代码有可能是错的。 |
create service if not exists user_security_service ( 前端URL我也想驼峰访问,这样就统一了(URL,参数,SQL,Service 类全统一了) |
如果不用自动生成service功能而是手写services.sql,还得搞个驼峰转下划线的工具快速转换。 |
自动生成代码这个在 idea 中不太好用,尤其是修改方法名时。idea 项目中任何代码有问题会导致 HelloSqlScriptTest 都无法运行了。需要手动删代码如何在改。 |
用 set DATABASE_TO_UPPER false 如果你一直遵循 sql 中的方法名和参数名都是下滑线,生成的 java 代码就是驼峰,当你需要改名字时,先改 sql 然后自动生成新的服务接口。如果你改 java 代码再改 sql 那用 sql 定义接口就没意义了。 |
发现还是有问题,如果是这种写法 get_user_security_by_user_id(user_id long) user_security,
delete_user_security_by_user_id(user_id long) void, 前端传参数必须用下划线了。这样不太好。(假如:我前端数据的字段都是驼峰,如果有自动传字段名的功能还得在前端把驼峰字段转换成下划线才行) |
//第一种
export function getUserSecurityByUserId(userId) {
return axios.post('/service/user_security_service/get_user_security_by_user_id', {user_id: userId})
}
//第二种
export function getUserSecurityByUserId(userId) {
return axios.post('/service/userSecurityService/getUserSecurityByUserId', {userId})
} 前端使用如果是第一种真的很麻烦 |
约定的惯例就是 sql 和 url 用下划线,js 和 java 的代码用驼峰。 |
或许你可以考虑用一下 lealone-rpc.js var userService = lealone.getService("user_security_service");
export function getUserSecurityByUserId(userId) {
return userService.getUserSecurityByUserId(userId)
} lealone-rpc.js 就是封装了 axios |
如果你想所有地方都用驼峰,就用 set DATABASE_TO_UPPER false @Override
public Object executeService(String methodName, Map<String, Object> methodArgs) {
switch (methodName) {
case "addUser":
String p_name_1 = toString("name", methodArgs);
Integer p_age_1 = toInt("age", methodArgs);
return si.addUser(p_name_1, p_age_1);
case "findByName":
String p_name_2 = toString("name", methodArgs);
return si.findByName(p_name_2);
default:
throw noMethodException(methodName);
}
} |
可以太爽了,我就是想把所有的代码改成和java一样驼峰。包括数据库字段 |
lealone的微服务和dubbo比确实好用,因为 dubbo 需要写定义文件。但是相对 spring cloud比,spring cloud是不需要写定义文件的。都是 java 类重构改名非常方便。
现在写 services.sql 主要是大小写下划线的问题,由于没有自动生成代码了。都是先写 Service类在写 services.sql 直接复制过来还得都改成下划线的,就非常痛苦。
The text was updated successfully, but these errors were encountered: