继成父类后参数封装,封装失败


spring-boot mybatis-plus的项目中会添加一个controller,定义好curd的功能,然后其他controller继承,自动实现curd的功能

MpCurdController.java

package com.litong.spring.boot.v158.mp.layui.v255.controller;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.litong.spring.boot.v158.mp.utils.LayuiUtils;
import com.litong.spring.boot.v158.mp.vo.JsonBean;
import com.litong.spring.boot.v158.mp.vo.PageJsonBean;
import com.litong.utils.array.LArrays;
import com.litong.utils.reflection.LReflectionUtils;
import com.litong.utils.string.StringUtil;
import lombok.extern.slf4j.Slf4j;
/**
 * @author bill robot
 * @date 2020年6月10日_上午10:37:50 
 * @version 1.0 
 * @desc
 */
@Slf4j
public class MpCurdController<Service extends IService<Entity>, Entity> {
  @Autowired
  private Service s;
  @RequestMapping("list")
  public PageJsonBean<Entity> list(@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
      @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, String orderBy, boolean isAsc,Entity e) {
    e = LReflectionUtils.convertEmpytStringToNull(e);
    log.info("pageSize:{},pageNo:{},e {}", pageSize, pageNo, e);
    Map<String, Object> map = LReflectionUtils.convertObjectToMap(e);
    QueryWrapper<Entity> queryWrapper = new QueryWrapper<>();
    if (orderBy != null) {
      queryWrapper.orderBy(true, isAsc, orderBy);
    }
    for (Map.Entry<String, Object> m : map.entrySet()) {
      if (m.getKey().equals("id")) {
        queryWrapper.eq("id", m.getValue());
      } else {
        queryWrapper.like(m.getKey(), m.getValue());
      }
    }
    Page<Entity> page = new Page<>(pageNo, pageSize);
    IPage<Entity> result = s.page(page, queryWrapper);
    PageJsonBean<Entity> pageJsonBean = new PageJsonBean<>(result);
    return pageJsonBean;
  }
  @RequestMapping("listColumn")
  public JsonBean<List<Entity>> listColumn(String column, Entity e) {
    String mName = "listColumn";
    log.info("{},column {} entity {}", mName, column, e);
    QueryWrapper<Entity> queryWrapper = new QueryWrapper<Entity>();
    queryWrapper.select("id", column);
    Map<String, Object> map = LReflectionUtils.convertObjectToMap(e);
    for (Map.Entry<String, Object> m : map.entrySet()) {
      if (m.getKey().equals("id")) {
        queryWrapper.eq("id", m.getValue());
      } else {
        queryWrapper.like(m.getKey(), m.getValue());
      }
    }
    List<Entity> list = s.list(queryWrapper);
    JsonBean<List<Entity>> jsonBean = new JsonBean<>(list);
    return jsonBean;
  }
  @RequestMapping("getById")
  public JsonBean<Entity> get(String id) {
    log.info("get by id {}", id);
    Entity byId = s.getById(id);
    JsonBean<Entity> jsonBean = new JsonBean<>(byId);
    return jsonBean;
  }
  @RequestMapping("removeById")
  public JsonBean<Boolean> removeById(String id) {
    String methodName = "removeById";
    log.info("{} by id {}", methodName, id);
    boolean isNumeric = StringUtil.isNumeric(id);
    boolean b = false;
    if (isNumeric) {
      b = s.removeById(Integer.parseInt(id));
    } else {
      b = s.removeById(id);
    }
    return buildJsonBean(methodName, b);
  }
  @RequestMapping("removeByIds")
  public JsonBean<Boolean> removeByIds(@RequestParam(value = "ids[]") String[] ids) {
    String methodName = "removeByIds";
    log.info("{} {}", methodName, ids);
    if (ids.length < 1) {
      return new JsonBean<Boolean>();
    }
    boolean isNumeric = StringUtil.isNumeric(ids[0]);
    List<? extends Serializable> idList = null;
    if (isNumeric) {
      int[] intIds = new int[ids.length];
      for (int i = 0; i < ids.length; i++) {
        intIds[i] = Integer.parseInt(ids[i]);
      }
      idList=LArrays.toList(intIds);
    } else {
      idList = LArrays.toList(ids);
    }
    boolean b = s.removeByIds(idList);
    return buildJsonBean(methodName, b);
  }
  @RequestMapping("save")
  public JsonBean<Boolean> save(Entity e) {
    String methodName = "save";
    log.info("{} {}", methodName, e);
    boolean b = s.saveOrUpdate(e);
    return buildJsonBean(methodName, b);
  }
  @RequestMapping("update")
  public JsonBean<Boolean> update(Entity e) {
    String methodName = "update";
    log.info("{} {}", methodName, e);
    boolean b = s.saveOrUpdate(e);
    return buildJsonBean(methodName, b);
  }
  @RequestMapping("saveOrUpdate")
  public JsonBean<Boolean> saveOrUpdate(Entity e) {
    String methodName = "saveOrUpdate";
    log.info("{} {}", methodName, e);
    boolean b = s.saveOrUpdate(e);
    return buildJsonBean(methodName, b);
  }
  public JsonBean<Boolean> buildJsonBean(String methodName, boolean b) {
    return LayuiUtils.buildJsonBean(methodName,b);
  }
}


其他的controller集成

package com.litong.spring.boot.v158.layui.v255.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.litong.spring.boot.v158.layui.v255.entity.FormComplaint;
import com.litong.spring.boot.v158.layui.v255.service.FormComplaintService;
import com.litong.spring.boot.v158.mp.layui.v255.controller.MpCurdController;
/**
 * <p>
 * 投诉单 前端控制器
 * </p>
 *
 * @author litong
 * @since 2020-06-01
 */
@RestController
@RequestMapping("/formComplaint")
public class FormComplaintController extends MpCurdController<FormComplaintService,FormComplaint> {
  
}


我上面的功能移植到jfinal中遇到了问题,下面的移植的步骤和遇到的问题

父controler,保存数据

package com.litong.jfinal.controller;
import com.jfinal.core.Controller;
import com.jfinal.core.paragetter.Para;
import com.jfinal.plugin.activerecord.Model;
import com.litong.layui.vo.JsonBean;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class LayuiCurdControler<E extends Model<E>> extends Controller {
  public void saveOrUpdate(@Para("")E e) {
    log.info("e:{}",e);
    renderJson(new JsonBean<String>("test success"));
  }
}

子类继承

package com.litong.db.controller;
import com.litong.db.monitoring.common.model.DbConnectInfo;
import com.litong.jfinal.controller.LayuiCurdControler;
public class DbConnectInfoController extends LayuiCurdControler<DbConnectInfo>{
}


定义路由

package com.litong.jfinal.route;
import com.jfinal.config.Routes;
import com.litong.db.controller.DbConnectInfoController;
import com.litong.jfinal.controller.PathController;
public class BackendRoutes extends Routes {
  public void config() {
    add("/path", PathController.class);
    add("/DbConnectInfo",DbConnectInfoController.class);
  }
}

启动测试

http://192.168.0.10:11029/litongjava-jfinal-monitoring-db/DbConnectInfo/saveOrUpdate?jdbcUrl=xx&jdbcUser=xx&jdbcPswd=xx


严重: com.litong.jfinal.controller.LayuiCurdControler.saveOrUpdate(E) : /DbConnectInfo/saveOrUpdate?jdbcUrl=xx&jdbcUser=xx&jdbcPswd=xx

java.lang.RuntimeException: java.lang.InstantiationException
at com.jfinal.core.Injector.createInstance(Injector.java:39)
at com.jfinal.core.Injector.injectModel(Injector.java:90)
at com.jfinal.core.Controller.getModel(Controller.java:778)
at com.jfinal.core.paragetter.ModelGetter.get(ModelGetter.java:30)
at com.jfinal.core.paragetter.ParaProcessor.get(ParaProcessor.java:51)
at com.jfinal.aop.Invocation.<init>(Invocation.java:86)
at com.jfinal.core.ActionHandler.handle(ActionHandler.java:90)
at com.jfinal.core.JFinalFilter.doFilter(JFinalFilter.java:89)
at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.SessionRestoringHandler.handleRequest(SessionRestoringHandler.java:119)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:292)
at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:138)
at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:272)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:81)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:104)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:364)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.InstantiationException
at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at com.jfinal.core.Injector.createInstance(Injector.java:37)
... 38 more

问题出现在参数封装中





评论区

JFinal

2020-08-01 10:39

异常出在 com.jfinal.core.Injector 的下面方法中:
private static T createInstance(Class objClass) {
try {
return objClass.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

而这个方法本质只有一行代码 objClass.newInstance();

应该是你的这个类不允许 newInstance(),检查无参构造方法是否存在

李通

2020-08-01 11:05

无参构造方法 不存储在,因为没有获取到正常的类,我录制了一个详细问题的视频,如何上传

JFinal

2020-08-01 12:18

@李通 上传到 B 站这类网站,在此给出链接即可

李通

2020-08-01 14:23

@JFinal
https://www.bilibili.com/video/BV1i5411a7Hd
视频如上,测试在子类中正常,在父类中不行

JFinal

2020-08-01 17:38

@李通 通过看你的视频,得知问题其实很明显, Model 是一个抽象类,是不允许被创建实例的,所以 objClass.newInstance() 必然报异常

你在 spring 中能用,很可能是因为你在 spring 中创建的类并 "不是抽象类",而是一个具体类,也就是说 spring 中你能获取到传入泛型的具体类型,而在 jfinal 中你没有获取到

没有获取到的原因很可能是泛型获取的时间太早了,因为 controller 中 action 的初始化是在启动时进行的

你试着将 LayuiCurdControler 改成不用 action 参数注入而是使用 getBean 来解决:
public class LayuiCurdControler 《E extends Model《E》》 extends Controller {
public void saveOrUpdate() {
Class beanClass = getBeanClass();
Model model = getBean(beanClass, "", true);
renderJson(...);
}
}

以上有两个关键点:
1: saveOrUpdate 方法不要给定形参,而是在方法体内部用 getBean或者 getModel 来实现

2:通过 getBeanClass() 来获取当前泛型传递过来的具体类型,具体到你演示的例子中,值为 DbConnectionInfo.class

getBeanClass() 中可以利用 java 的一些反射 API 来获取

久伴轻尘

2020-08-03 08:52

@李通 https://gitee.com/jbqc/future-template-server/blob/master/future-org/src/main/java/com/jiubanqingchen/future/org/admin/ModelController.java
我这边有对curd功能的封装

李通

2020-08-03 17:23

@久伴轻尘 你定义了service,让我感到代码有些负载,model本身就可以操作数据库

李通

2020-08-03 17:26

@Final 问题已经解决,修改后的代码如下
```
package com.litong.jfinal.controller;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;

import com.jfinal.core.Controller;
import com.jfinal.plugin.activerecord.Model;
import com.litong.layui.vo.JsonBean;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class LayuiCurdControler> extends Controller {

private volatile Class clazz = null;

public void getEclassName() {
String name = getBeanClass().getName();
// String name = e.getClass().getName();
HashMap hashMap = new HashMap();
hashMap.put("className", name);
renderJson(hashMap);
}

@SuppressWarnings("unchecked")
public Class getBeanClass() {
if (clazz == null) {
Type type = this.getClass().getGenericSuperclass();
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
clazz = (Class) actualTypeArguments[0];
}
return clazz;
}

public void saveOrUpdate() {
Class beanClass = getBeanClass();
E e = getBean(beanClass, "");
log.info("e:{}", e);
e.save();
renderJson(new JsonBean("test success"));
}
}
```

李通

2020-08-03 17:26

我有了一个新的想法,前台将tableName 发送过来,后台使用Db进行封装

久伴轻尘

2020-08-03 18:22

@李通 我更倾向于在service中处理,保持一个干净的model或许会更好

久伴轻尘

2020-08-03 18:22

@李通 tableName可以通过model获取到的

热门反馈

扫码入社