Spring MVC转换如何

我有车辆服务,其中有零件清单。 添加新服务不是问题,查看服务不是问题,但是当我尝试实现编辑时,它不会预先选择部件列表。 因此,我认为这是一个Thymeleaf问题,我在这里发布问题。

我得到的答案是尝试实现弹簧转换服务。 我做到了(我想),现在我需要帮助让我摆脱这个烂摊子。 问题是视图将来自服务的零件实例与包含所有零件的零件实例的零件实例进行比较,并且从不使用转换器,因此它不起作用。 我没有收到错误……只是在视图中,未选择部件。 您将找到转换器,WebMVCConfig,PartRepository,ServiceController和html w / thymeleaf,供您参考。 我究竟做错了什么???

转换器:

PartToString:

public class PartToStringConverter implements Converter { /** The string that represents null. */ private static final String NULL_REPRESENTATION = "null"; @Resource private PartRepository partRepository; @Override public String convert(final Part part) { if (part.equals(NULL_REPRESENTATION)) { return null; } try { return part.getId().toString(); } catch (NumberFormatException e) { throw new RuntimeException("could not convert `" + part + "` to an valid id"); } } } 

StringToPart:

 public class StringToPartConverter implements Converter { /** The string that represents null. */ private static final String NULL_REPRESENTATION = "null"; @Resource private PartRepository partRepository; @Override public Part convert(final String idString) { if (idString.equals(NULL_REPRESENTATION)) { return null; } try { Long id = Long.parseLong(idString); return this.partRepository.findByID(id); } catch (NumberFormatException e) { throw new RuntimeException("could not convert `" + id + "` to an valid id"); } } } 

WebMvcConfig的相关部分:

 @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { ... @Bean(name="conversionService") public ConversionService getConversionService(){ ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean(); bean.setConverters(getConverters()); bean.afterPropertiesSet(); ConversionService object = bean.getObject(); return object; } private Set getConverters() { Set converters = new HashSet(); converters.add(new PartToStringConverter()); converters.add(new StringToPartConverter()); System.out.println("converters added"); return converters; } } 

零件存储库如下所示:

 @Repository @Transactional(readOnly = true) public class PartRepository { protected static Logger logger = Logger.getLogger("repo"); @PersistenceContext private EntityManager entityManager; @Transactional public Part update(Part part){ try { entityManager.merge(part); return part; } catch (PersistenceException e) { return null; } } @SuppressWarnings("unchecked") public List getAllParts(){ try { return entityManager.createQuery("from Part").getResultList(); } catch (Exception e) { return new ArrayList(); } } public Part findByID(Long id){ try { return entityManager.find(Part.class, id); } catch (Exception e) { return new Part(); } } } 

编辑ServiceController的一部分:

  @Controller @RequestMapping("/") public class ServisController { protected static Logger logger = Logger.getLogger("controller"); @Autowired private ServisRepository servisRepository; @Autowired private ServisTypeRepository servisTypeRepo; @Autowired private PartRepository partRepo; @Autowired private VehicleRepository2 vehicleRepository; /*-- **************************************************************** -*/ /*-- Editing servis methods -*/ /*-- -*/ /*-- **************************************************************** -*/ @RequestMapping(value="/admin/servisi/editServis", method = RequestMethod.GET) public String getEditServis(@RequestParam(value="id", required=true) Long id, Model model){ logger.debug("Received request to show edit page"); List servisTypeList = servisTypeRepo.getAllST(); List partList = partRepo.getAllParts(); List selectedParts = new ArrayList(); Servis s = servisRepository.getById(id); for (Part part : partList) { for (Part parts : s.getParts()) { if(part.getId()==parts.getId()){ selectedParts.add(part); System.out.println(part); } } } s.setParts(selectedParts); logger.debug("radjeni dijelovi " + s.getParts().toString()); logger.debug("radjeni dijelovi " + s.getParts().size()); s.setVehicle(vehicleRepository.findByVin(s.getVehicle().getVin())); model.addAttribute("partsAtribute", partList); model.addAttribute("servisTypesAtribute", servisTypeList); model.addAttribute("servisAttribute", s); return "/admin/servis/editServis"; } @RequestMapping(value="/admin/servisi/editServis", method = RequestMethod.POST) public String saveEditServis(@ModelAttribute("servisAttribute") @Valid Servis servis, BindingResult result){ logger.debug("Received request to save edit page"); if (result.hasErrors()) { String ret = "/admin/servis/editServis"; return ret; } servisRepository.update(servis); return "redirect:/admin/servisi/listServis?id="+servis.getVehicle().getVin(); } } 

视图正确显示服务,只是它不预先选择部件。

editService:

    Edit Vehicle Service   

Incorrect LP

Incorrect Date

Vrsta Servisa

Incorrect VIN

Part name and serial No.

Incorrect part ID

Yes No

Incorrect checkbox


Cancel

更新:在Avnish的帮助下,我做了几处修改,这就是我回来的内容:

添加转换服务不起作用,所以在研究和阅读文档之后,回过头来改变我的WebMvcConfig文件,而不是@Bean我添加了这个(我只需查看WebMvcConfigurationSupport上的文档:

 @Override protected void addFormatters(FormatterRegistry registry){ registry.addFormatter(new PartTwoWayConverter()); } 

然后我删除了我的转换器,并制作了一个完成魔术的格式化程序。 不要被名字弄糊涂,它是形成者:

 public class PartTwoWayConverter implements Formatter{ /** The string that represents null. */ private static final String NULL_REPRESENTATION = "null"; @Resource private PartRepository partRepository; public PartTwoWayConverter(){ super(); } public Part parse(final String text, final Locale locale) throws ParseException{ if (text.equals(NULL_REPRESENTATION)) { return null; } try { Long id = Long.parseLong(text); // Part part = partRepository.findByID(id); // this does not work with controller Part part = new Part(); // this works part.setId(id); // return part; } catch (NumberFormatException e) { throw new RuntimeException("could not convert `" + text + "` to an valid id"); } } public String print(final Part part, final Locale locale){ if (part.equals(NULL_REPRESENTATION)) { return null; } try { return part.getId().toString(); } catch (NumberFormatException e) { throw new RuntimeException("could not convert `" + part + "` to an valid id"); } } } 

然后我编辑了我的HTML。 无法使百里香叶成功,所以我这样做了:

 
Part name and serial No.

Incorrect part ID

最后,经过很多麻烦和转换错误,我无法弄清楚,改变了我的控制器更新方法:

 @RequestMapping(value="/admin/servisi/editServis", method = RequestMethod.POST) public String saveEditServis(@ModelAttribute("servisAttribute") @Valid Servis servis, BindingResult result){ logger.debug("Received request to save edit page"); if (result.hasErrors()) { logger.debug(result); String ret = "/admin/servis/editServis"; return ret; } List list = new ArrayList(); for (Part part : servis.getParts()) { list.add(partRepo.findByID(part.getId())); } Servis updating = servisRepository.getById(servis.getId()); updating.setCompleted(servis.getCompleted()); updating.setParts(list); // If just setting servis.getParts() it does not work updating.setServiceDate(servis.getServiceDate()); updating.setServiceType(servis.getServiceType()); servisRepository.update(updating); return "redirect:/admin/servisi/listServis?id="+servis.getVehicle().getVin(); } 

即使这有效,我仍然不高兴,因为这段代码看起来更像是修补而不是正确的编码。 仍然困惑为什么从partRepository返回Part不起作用。 为什么百里香不起作用……如果有人能把我送到正确的方向,我将非常感激!

Thymeleaf使用spring框架SelectedValueComparator.isSelected来比较值(包含选项html中的selected =“selected”标签),该框架本身首先依赖于java相等性。 如果失败,则返回两个值的String表示。 以下摘自其文档


用于测试候选值是否与数据绑定值匹配的实用程序类。 热切地试图通过多种途径来certificate比较,以处理诸如实例不等式,逻辑(基于字符串表示)的平等和基于PropertyEditor的比较等问题。
完全支持比较数组,集合和地图。
平等合同
对于单值对象,首先使用标准Java相等性来测试相等性。 因此,用户代码应该努力实现Object.equals以加速比较过程。 如果Object.equals返回false,则尝试进行详尽的比较,目的是certificate平等而不是反驳它。
接下来,尝试比较候选值和绑定值的字符串表示。 在许多情况下,这可能导致为真,因为当向用户显示时,两个值都将表示为字符串。
接下来,如果候选值是String,则尝试将绑定值与将相应的PropertyEditor应用于候选的结果进行比较。 此比较可以执行两次,一次针对直接String实例,然后针对String表示,如果第一次比较结果为false。


对于您的具体情况,我会写下转换服务,以便我的部分对象转换为字符串,如http://www.thymeleaf.org/doc/html/Thymeleaf-Spring3.html#configuring-a-中的 VarietyFormatter所述。转换服务 。 发布这个我使用th:value =“$ {part}”并让SelectedValueComparator做比较对象和在html中添加selected =“selected”部分的魔力。

同样在我的设计中,我总是实现基于主键的equals方法(通常我在我的顶级抽象实体中执行它,所有其他实体都从该实体inheritance)。 这进一步强化了我的系统中域对象的自然比较。 你在设计中做了类似的事吗?

希望能帮助到你!!