视图上的 select2 自动完成错误 (spring roo rc1)
select2 autocomplete error on views (spring roo rc1)
我在使用 RC1 生成项目时没有任何问题。在对该项目进行一些工作后,我意识到使用 select2 自动完成的 CRUD 字段突然停止工作。当 s2 尝试从 /entity/s2 路径获取数据时出现错误 500。
完整 java 控制台错误:
2017-03-09 11:20:46.136 WARN 42495 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No converter found capable of converting from type [ar.edu.um.programacion2.oficios.reference.Disponibilidad] to type [java.lang.String] (through reference chain: io.springlets.data.web.select2.Select2DataWithConversion["results"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No converter found capable of converting from type [ar.edu.um.programacion2.oficios.reference.Disponibilidad] to type [java.lang.String] (through reference chain: io.springlets.data.web.select2.Select2DataWithConversion["results"])
2017-03-09 11:20:46.137 WARN 42495 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No converter found capable of converting from type [ar.edu.um.programacion2.oficios.reference.Disponibilidad] to type [java.lang.String] (through reference chain: io.springlets.data.web.select2.Select2DataWithConversion["results"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No converter found capable of converting from type [ar.edu.um.programacion2.oficios.reference.Disponibilidad] to type [java.lang.String] (through reference chain: io.springlets.data.web.select2.Select2DataWithConversion["results"])
任何引用字段的字段现在都不起作用。这是在该字段中用作参考的实体之一:
@RooJavaBean
@RooToString
@RooJpaEntity
@RooEquals(isJpaEntity = true)
public class Localidad {
public Localidad(String nombre, String descripcion) {
super();
this.nombre = nombre;
this.descripcion = descripcion;
}
/**
* TODO Auto-generated attribute documentation
*
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/**
* TODO Auto-generated attribute documentation
*
*/
@Version
private Integer version;
/**
* TODO Auto-generated attribute documentation
*
*/
@NotNull
private String nombre;
/**
* TODO Auto-generated attribute documentation
*
*/
private String descripcion;
private String googleMapsString;
/**
* TODO Auto-generated method documentation
*
* @return String
*/
public String toString() {
return getNombre();
}
public String getMapString(){
return "http://maps.googleapis.com/maps/api/staticmap?" + getGoogleMapsString() + "&key=";
}
}
使用引用字段的class:
@RooJavaBean
@RooToString
@RooJpaEntity
@RooEquals(isJpaEntity = true)
public class Servicio {
/**
* TODO Auto-generated attribute documentation
*
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/**
* TODO Auto-generated attribute documentation
*
*/
@Version
private Integer version;
/**
* TODO Auto-generated attribute documentation
*
*/
@NotNull
private String nombre;
/**
* TODO Auto-generated attribute documentation
*
*/
private String descripcion;
/**
* TODO Auto-generated attribute documentation
*
*/
@RooUploadedFile(contentType = "image/png")
@Lob
private byte[] logo;
/**
* TODO Auto-generated attribute documentation
*
*/
@NotNull
private String telefono;
/**
* TODO Auto-generated attribute documentation
*
*/
@NumberFormat
private float puntaje;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="localidad_id")
private Localidad localidad;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="disponibilidad_id")
private Disponibilidad disponibilidad;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="categoria_id")
private Categoria categoria;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="prestador_id")
private Prestador prestador;
@ManyToMany
@JoinTable(name = "servicio_calificacion", joinColumns = @JoinColumn(name = "servicio_id"), inverseJoinColumns = @JoinColumn(name = "calificacion_id"))
private List<CalificacionCliente> listadecalificaciones;
/**
* TODO Auto-generated method documentation
*
* @return String
*/
public String toString() {
return getNombre() + " (" + getPrestador() + ")";
}
}
其中一个观点是使用了该字段:
<!DOCTYPE html>
<html lang="en" data-layout-decorate="~{layouts/default-layout}">
<head id="head">
<title data-th-text="#{label_create_entity(#{label_servicio})}">
Create Servicio - oficios - SpringRoo Application</title>
<!-- DateTimePicker -->
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.4/build/jquery.datetimepicker.min.css" data-th-href="@{/webjars/datetimepicker/build/jquery.datetimepicker.min.css}" />
</head>
<body id="body">
<header role="banner">
<!-- Content replaced by layout of the page displayed -->
</header>
<!-- CONTAINER -->
<div class="container bg-container">
<!-- CONTENT -->
<!--
Only the inner content of the following tag "section" is included
within the template, in the section "content"
-->
<section data-layout-fragment="content">
<div class="container-fluid content" data-th-with="collectionLink=${@linkBuilder.of('ServiciosCollectionThymeleafController')}">
<h1 data-th-text="#{label_create_entity(#{label_servicio})}">Create Servicio</h1>
<!-- FORM -->
<form class="form-horizontal validate" method="POST" data-th-object="${servicio}" data-th-action="@{${collectionLink.to('create').with('servicio', servicio.id)}}">
<fieldset id="containerFields">
<legend class="sr-only" data-th-text="#{label_data_entity(#{label_servicio})}">Servicio data </legend>
<div class="form-group has-error has-feedback" data-z="15c04ac1" id="servicio-nombre-field" data-th-classappend="${#fields.hasErrors('nombre')}? 'has-error has-feedback'" data-th-class="form-group">
<label for="nombre" class="col-md-3 control-label" data-th-text="#{label_servicio_nombre}">nombre</label>
<div class="col-md-6">
<input id="nombre" name="nombre" data-th-value="*{{nombre}}" type="text" class="form-control" placeholder="nombre" data-th-placeholder="#{label_servicio_nombre}" data-toggle="tooltip" aria-describedby="nombreStatus" required="required" />
<span data-th-classappend="${#fields.hasErrors('nombre')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('nombre')}" aria-hidden="true"></span>
<span id="nombre-error" class="help-block" data-th-if="${#fields.hasErrors('nombre')}" data-th-errors="*{nombre}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="8d2c287d" id="servicio-descripcion-field" data-th-classappend="${#fields.hasErrors('descripcion')}? 'has-error has-feedback'" data-th-class="form-group">
<label for="descripcion" class="col-md-3 control-label" data-th-text="#{label_servicio_descripcion}">descripcion</label>
<div class="col-md-6">
<input id="descripcion" name="descripcion" data-th-value="*{{descripcion}}" type="text" class="form-control" placeholder="descripcion" data-th-placeholder="#{label_servicio_descripcion}" data-toggle="tooltip" aria-describedby="descripcionStatus" />
<span data-th-classappend="${#fields.hasErrors('descripcion')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('descripcion')}" aria-hidden="true"></span>
<span id="descripcion-error" class="help-block" data-th-if="${#fields.hasErrors('descripcion')}" data-th-errors="*{descripcion}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="54220f01" id="servicio-logo-field" data-th-classappend="${#fields.hasErrors('logo')}? 'has-error has-feedback'" data-th-class="form-group">
<label for="logo" class="col-md-3 control-label" data-th-text="#{label_servicio_logo}">logo</label>
<div class="col-md-3">
<input id="logo" name="logo" data-th-value="*{{logo}}" type="text" class="form-control inputmask" placeholder="logo" data-th-placeholder="#{label_servicio_logo}" data-toggle="tooltip" aria-describedby="logoStatus" data-inputmask-alias="numeric" data-inputmask-digits="2" />
<span data-th-classappend="${#fields.hasErrors('logo')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('logo')}" aria-hidden="true"></span>
<span id="logo-error" class="help-block" data-th-if="${#fields.hasErrors('logo')}" data-th-errors="*{logo}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="f1acb8e1" id="servicio-telefono-field" data-th-classappend="${#fields.hasErrors('telefono')}? 'has-error has-feedback'" data-th-class="form-group">
<label for="telefono" class="col-md-3 control-label" data-th-text="#{label_servicio_telefono}">telefono</label>
<div class="col-md-6">
<input id="telefono" name="telefono" data-th-value="*{{telefono}}" type="text" class="form-control" placeholder="telefono" data-th-placeholder="#{label_servicio_telefono}" data-toggle="tooltip" aria-describedby="telefonoStatus" required="required" />
<span data-th-classappend="${#fields.hasErrors('telefono')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('telefono')}" aria-hidden="true"></span>
<span id="telefono-error" class="help-block" data-th-if="${#fields.hasErrors('telefono')}" data-th-errors="*{telefono}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="3c00987d" id="servicio-localidad-field" data-th-classappend="${#fields.hasErrors('localidad')}? 'has-error has-feedback'" data-th-class="form-group" data-th-with="collectionLink=${@linkBuilder.of('LocalidadsCollectionThymeleafController')}">
<label for="localidad" class="col-md-3 control-label" data-th-text="#{label_servicio_localidad}">Localidad</label>
<div class="col-md-6">
<!-- Select2 -->
<select data-th-field="*{localidad}" class="form-control dropdown-select-ajax" data-allow-clear="true" data-data-ajax--url="${collectionLink.to('select2')}" data-ajax--cache="true" data-ajax--delay="250" data-ajax--data-type="json" data-data-placeholder="#{info_select_an_option}">
<option data-th-unless="*{localidad} == null" data-th-value="*{localidad.id}" data-th-text="*{{localidad}}" selected="selected">Localidad</option>
</select>
<span data-th-classappend="${#fields.hasErrors('localidad')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('localidad')}" aria-hidden="true"></span>
<span id="localidad-error" class="help-block" data-th-if="${#fields.hasErrors('localidad')}" data-th-errors="*{localidad}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="19c21a81" id="servicio-disponibilidad-field" data-th-classappend="${#fields.hasErrors('disponibilidad')}? 'has-error has-feedback'" data-th-class="form-group" data-th-with="collectionLink=${@linkBuilder.of('DisponibilidadsCollectionThymeleafController')}">
<label for="disponibilidad" class="col-md-3 control-label" data-th-text="#{label_servicio_disponibilidad}">Disponibilidad</label>
<div class="col-md-6">
<!-- Select2 -->
<select data-th-field="*{disponibilidad}" class="form-control dropdown-select-ajax" data-allow-clear="true" data-data-ajax--url="${collectionLink.to('select2')}" data-ajax--cache="true" data-ajax--delay="250" data-ajax--data-type="json" data-data-placeholder="#{info_select_an_option}">
<option data-th-unless="*{disponibilidad} == null" data-th-value="*{disponibilidad.id}" data-th-text="*{{disponibilidad}}" selected="selected">Disponibilidad</option>
</select>
<span data-th-classappend="${#fields.hasErrors('disponibilidad')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('disponibilidad')}" aria-hidden="true"></span>
<span id="disponibilidad-error" class="help-block" data-th-if="${#fields.hasErrors('disponibilidad')}" data-th-errors="*{disponibilidad}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="1d95a73d" id="servicio-categoria-field" data-th-classappend="${#fields.hasErrors('categoria')}? 'has-error has-feedback'" data-th-class="form-group" data-th-with="collectionLink=${@linkBuilder.of('CategoriasCollectionThymeleafController')}">
<label for="categoria" class="col-md-3 control-label" data-th-text="#{label_servicio_categoria}">Categoria</label>
<div class="col-md-6">
<!-- Select2 -->
<select data-th-field="*{categoria}" class="form-control dropdown-select-ajax" data-allow-clear="true" data-data-ajax--url="${collectionLink.to('select2')}" data-ajax--cache="true" data-ajax--delay="250" data-ajax--data-type="json" data-data-placeholder="#{info_select_an_option}">
<option data-th-unless="*{categoria} == null" data-th-value="*{categoria.id}" data-th-text="*{{categoria}}" selected="selected">Categoria</option>
</select>
<span data-th-classappend="${#fields.hasErrors('categoria')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('categoria')}" aria-hidden="true"></span>
<span id="categoria-error" class="help-block" data-th-if="${#fields.hasErrors('categoria')}" data-th-errors="*{categoria}">Error message.</span>
</div>
</div>
</fieldset>
<!-- buttons form -->
<div class="form-group">
<div class="col-md-9 col-md-offset-3">
<button type="submit" class="btn btn-primary" data-th-text="#{label_save}">Save</button>
<button type="reset" class="btn btn-default" onclick="window.history.back()" data-th-text="#{label_reset}">Cancel</button>
</div>
</div>
</form>
<!-- /FORM -->
</div>
</section>
<!-- /CONTENT -->
</div>
<!-- /CONTAINER -->
<footer class="container">
<!-- Content replaced by layout of the page displayed -->
</footer>
<!-- JavaScript
================================================== -->
<!-- Placed at the end of the document so that the pages load faster -->
<!-- JavaScript loaded by layout of the page displayed -->
<!--
Only the inner content of the following tag "javascript" is included
within the template, in the div "javascript"
-->
<div data-layout-fragment="javascript">
<!-- DateTimePicker -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.4/build/jquery.datetimepicker.full.min.js" data-th-src="@{/webjars/datetimepicker/build/jquery.datetimepicker.full.min.js}"></script>
<script src="../../static/public/js/datetimepicker-defaults.js" data-th-src="@{/public/js/datetimepicker-defaults.js}"></script>
<!-- jquery.inputmask -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.inputmask/3.3.1/jquery.inputmask.bundle.min.js" data-th-src="@{/webjars/jquery.inputmask/min/jquery.inputmask.bundle.min.js}"></script>
<script type="text/javascript" data-th-inline="javascript">
(function(jQuery) {
jQuery(document)
.ready(
function() {
Inputmask
.extendAliases({
'numeric' : {
'groupSeparator' : /*[[#{label_inputmask_groupSeparator}]]*/'.',
'radixPoint' : /*[[#{label_inputmask_radixPoint}]]*/','
},
'currency' : {
'prefix' : /*[[#{label_inputmask_prefix}]]*/'',
'suffix' : /*[[#{label_inputmask_suffix}]]*/' €'
}
});
});
})(jQuery);
</script>
<script src="../../static/public/js/inputmask-defaults.js" data-th-src="@{/public/js/inputmask-defaults.js}"></script>
<!-- JQuery Validation -->
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/jquery.validate.min.js" data-th-src="@{/webjars/jquery-validation/dist/jquery.validate.min.js}">
</script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/additional-methods.min.js" data-th-src="@{/webjars/jquery-validation/dist/additional-methods.min.js}">
</script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/localization/messages_es.js" data-th-src="@{/webjars/jquery-validation/src/localization/messages_}+${#locale.language}+'.js'" data-th-if="${#locale.language} != 'en'">
</script>
<script src="../../static/public/js/validation-defaults.js" data-th-src="@{/public/js/validation-defaults.js}">
</script>
<script type="text/javascript" data-th-inline="javascript">
(function(jQuery) {
jQuery(document)
.ready(
function() {
jQuery
.extend(
jQuery.validator.messages,
{
'dateformat' : /*[[#{error_invalid_date}]]*/'Please enter a correct date/time',
'inputmask' : /*[[#{error_invalid_maskValue}]]*/'Please enter a valid value',
});
});
})(jQuery);
</script>
</div>
</body>
</html>
Log.roo
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-06 20:50:24
project setup --topLevelPackage ar.edu.um.programacion2.oficios --java 8
jpa setup --database MYSQL --provider HIBERNATE --hostName 127.0.0.1 --databaseName oficiosdb --userName root
entity jpa --class ~.reference.Persona
field string --fieldName username --unique
field string --fieldName password --notNull
field string --fieldName email --unique
field string --fieldName telefono
field file --fieldName avatar --contentType PNG
entity jpa --class ~.domain.Prestador --extends ~.reference.Persona
field string --fieldName razonsocial --notNull
field string --fieldName oficio --notNull
entity jpa --class ~.reference.Disponibilidad
field string --fieldName franjahoraria --notNull
field string --fieldName descripcion
entity jpa --class ~.reference.Localidad
field string --fieldName nombre --notNull
field string --fieldName descripcion
entity jpa --class ~.reference.Categoria
field string --fieldName nombre --notNull
field string --fieldName descripcion
enum type --class ~.reference.TipoCalif
enum constant --name POSITIVO
enum constant --name NEGATIVO
enum constant --name NEUTRAL
entity jpa --class ~.domain.Cliente --extends ~.reference.Persona
field string --fieldName nombre --notNull
field string --fieldName apellido --notNull
field string --fieldName domicilio
field string --fieldName domicilio2
entity jpa --class ~.domain.Calificacion
field string --fieldName comentario --notNull
field enum --fieldName tipo --type ~.reference.TipoCalif
entity jpa --class ~.domain.CalificacionCliente --extends ~.domain.Calificacion
entity jpa --class ~.domain.Servicio
field string --fieldName nombre --notNull
field string --fieldName descripcion
field file --fieldName logo --contentType PNG
field string --fieldName telefono --notNull
field number --fieldName puntaje --type float
entity jpa --class ~.domain.CalificacionPrestador --extends ~.domain.Calificacion
repository jpa --all
finder add --name findByTelefono --entity ~.domain.Servicio
finder add --name findByNombreLike --entity ~.domain.Servicio
finder add --name findByPuntaje --entity ~.domain.Servicio
finder add --name findByUsername --entity ~.domain.Cliente
finder add --name findByUsername --entity ~.domain.Prestador
finder add --name findByEmail --entity ~.domain.Cliente
finder add --name findByEmail --entity ~.domain.Prestador
service --all
web mvc setup
web mvc view setup --type THYMELEAF
web mvc controller --all --responseType THYMELEAF
web mvc templates setup --type THYMELEAF
web mvc language --code es --useAsDefault
// script --file script_roo
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-06 21:19:16
help
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-07 09:03:07
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-07 20:12:48
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 01:34:17
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 01:34:37
web mvc finder --entity ~.domain.Servicio
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 02:28:28
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 02:28:44
web mvc finder --all
web mvc finder --all
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 02:29:31
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 02:29:39
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 02:29:54
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 02:30:11
hint
help
web mvc finder --all
web mvc finder --entity ~.domain.Cliente
web mvc finder --all
web mvc finder --all --responseType THYMELEAF
web mvc finder --entity ~.domain.Servicio --responseType THYMELEAF
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 03:13:33
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 03:14:23
hint
hint finders
finder add --entity ~.domain.Servicio --name findByCategoria
finder add --entity ~.domain.Servicio --name queryByCategoria
finder add --entity ~.reference.Categoria --name findByNombre
security setup --provider SPRINGLETS_JPA
entity jpa --class ~.domain.Administrador --extends ~.reference.Persona
web mvc controller --entity ~.domain.Administrador
service --entity ~.domain.Administrador
repository jpa --entity ~.domain.Administrador
service --entity ~.domain.Administrador
web mvc controller --entity ~.domain.Administrador
web mvc controller --entity ~.domain.Administrador --responseType THYMELEAF
finder add --entity ~.reference.Persona --name findByUsername
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 08:02:54
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 21:06:10
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-09 09:30:10
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-09 10:08:32
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-09 15:51:20
注意: 首先我认为 spring 安全问题导致用户没有列出该实体的权限,但是当我授予用户权限时问题从错误 403 更改为我现在的 500。
之后我完全卡住了。我尝试再次生成所有视图,但没有效果。
谢谢
在您最后评论了您在 Spring 安全配置 class 中遇到的问题以及在转换器注册时出现的错误,我知道您的问题出在哪里。
几周前,我在 Spring 安全性中检测到一个问题,并在他们的存储库中创建了以下问题:
https://github.com/spring-projects/spring-security/issues/4202
似乎如果 @Configuration
class 扩展了 WebSecurityConfigurerAdapter
抽象 class(就像在 Spring Roo 生成的代码中一样),某些组件是在 formatters
已在 Spring 上下文中注册之前尝试 @Autowired
一个 ConversionService
实例,因此 addFormatters
方法不包含任何格式化程序。
一个简单的变通方法可以解决您的问题,您将能够在您的项目中使用 Spring 安全性是 @Override
生成的 setContentNegotiationStrategy
方法=18=] class 不包含 @Autowired
注释。
下面的例子看一下如何正确覆盖这个方法。 (在此示例中,代码已注释)
如果这能解决您的问题,那么您 comment on the issue 说您也有同样的问题就太好了。
希望对您有所帮助,感谢您提供的所有信息!
您可以在此处找到 java 中的 Select2 与示例一起使用 Url:http://www.javasolution.in/search/label/autocomplete 您可以在此处找到完整代码和说明
我在使用 RC1 生成项目时没有任何问题。在对该项目进行一些工作后,我意识到使用 select2 自动完成的 CRUD 字段突然停止工作。当 s2 尝试从 /entity/s2 路径获取数据时出现错误 500。
完整 java 控制台错误:
2017-03-09 11:20:46.136 WARN 42495 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No converter found capable of converting from type [ar.edu.um.programacion2.oficios.reference.Disponibilidad] to type [java.lang.String] (through reference chain: io.springlets.data.web.select2.Select2DataWithConversion["results"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No converter found capable of converting from type [ar.edu.um.programacion2.oficios.reference.Disponibilidad] to type [java.lang.String] (through reference chain: io.springlets.data.web.select2.Select2DataWithConversion["results"])
2017-03-09 11:20:46.137 WARN 42495 --- [nio-8080-exec-7] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No converter found capable of converting from type [ar.edu.um.programacion2.oficios.reference.Disponibilidad] to type [java.lang.String] (through reference chain: io.springlets.data.web.select2.Select2DataWithConversion["results"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No converter found capable of converting from type [ar.edu.um.programacion2.oficios.reference.Disponibilidad] to type [java.lang.String] (through reference chain: io.springlets.data.web.select2.Select2DataWithConversion["results"])
任何引用字段的字段现在都不起作用。这是在该字段中用作参考的实体之一:
@RooJavaBean
@RooToString
@RooJpaEntity
@RooEquals(isJpaEntity = true)
public class Localidad {
public Localidad(String nombre, String descripcion) {
super();
this.nombre = nombre;
this.descripcion = descripcion;
}
/**
* TODO Auto-generated attribute documentation
*
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/**
* TODO Auto-generated attribute documentation
*
*/
@Version
private Integer version;
/**
* TODO Auto-generated attribute documentation
*
*/
@NotNull
private String nombre;
/**
* TODO Auto-generated attribute documentation
*
*/
private String descripcion;
private String googleMapsString;
/**
* TODO Auto-generated method documentation
*
* @return String
*/
public String toString() {
return getNombre();
}
public String getMapString(){
return "http://maps.googleapis.com/maps/api/staticmap?" + getGoogleMapsString() + "&key=";
}
}
使用引用字段的class:
@RooJavaBean
@RooToString
@RooJpaEntity
@RooEquals(isJpaEntity = true)
public class Servicio {
/**
* TODO Auto-generated attribute documentation
*
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/**
* TODO Auto-generated attribute documentation
*
*/
@Version
private Integer version;
/**
* TODO Auto-generated attribute documentation
*
*/
@NotNull
private String nombre;
/**
* TODO Auto-generated attribute documentation
*
*/
private String descripcion;
/**
* TODO Auto-generated attribute documentation
*
*/
@RooUploadedFile(contentType = "image/png")
@Lob
private byte[] logo;
/**
* TODO Auto-generated attribute documentation
*
*/
@NotNull
private String telefono;
/**
* TODO Auto-generated attribute documentation
*
*/
@NumberFormat
private float puntaje;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="localidad_id")
private Localidad localidad;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="disponibilidad_id")
private Disponibilidad disponibilidad;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="categoria_id")
private Categoria categoria;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="prestador_id")
private Prestador prestador;
@ManyToMany
@JoinTable(name = "servicio_calificacion", joinColumns = @JoinColumn(name = "servicio_id"), inverseJoinColumns = @JoinColumn(name = "calificacion_id"))
private List<CalificacionCliente> listadecalificaciones;
/**
* TODO Auto-generated method documentation
*
* @return String
*/
public String toString() {
return getNombre() + " (" + getPrestador() + ")";
}
}
其中一个观点是使用了该字段:
<!DOCTYPE html>
<html lang="en" data-layout-decorate="~{layouts/default-layout}">
<head id="head">
<title data-th-text="#{label_create_entity(#{label_servicio})}">
Create Servicio - oficios - SpringRoo Application</title>
<!-- DateTimePicker -->
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.4/build/jquery.datetimepicker.min.css" data-th-href="@{/webjars/datetimepicker/build/jquery.datetimepicker.min.css}" />
</head>
<body id="body">
<header role="banner">
<!-- Content replaced by layout of the page displayed -->
</header>
<!-- CONTAINER -->
<div class="container bg-container">
<!-- CONTENT -->
<!--
Only the inner content of the following tag "section" is included
within the template, in the section "content"
-->
<section data-layout-fragment="content">
<div class="container-fluid content" data-th-with="collectionLink=${@linkBuilder.of('ServiciosCollectionThymeleafController')}">
<h1 data-th-text="#{label_create_entity(#{label_servicio})}">Create Servicio</h1>
<!-- FORM -->
<form class="form-horizontal validate" method="POST" data-th-object="${servicio}" data-th-action="@{${collectionLink.to('create').with('servicio', servicio.id)}}">
<fieldset id="containerFields">
<legend class="sr-only" data-th-text="#{label_data_entity(#{label_servicio})}">Servicio data </legend>
<div class="form-group has-error has-feedback" data-z="15c04ac1" id="servicio-nombre-field" data-th-classappend="${#fields.hasErrors('nombre')}? 'has-error has-feedback'" data-th-class="form-group">
<label for="nombre" class="col-md-3 control-label" data-th-text="#{label_servicio_nombre}">nombre</label>
<div class="col-md-6">
<input id="nombre" name="nombre" data-th-value="*{{nombre}}" type="text" class="form-control" placeholder="nombre" data-th-placeholder="#{label_servicio_nombre}" data-toggle="tooltip" aria-describedby="nombreStatus" required="required" />
<span data-th-classappend="${#fields.hasErrors('nombre')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('nombre')}" aria-hidden="true"></span>
<span id="nombre-error" class="help-block" data-th-if="${#fields.hasErrors('nombre')}" data-th-errors="*{nombre}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="8d2c287d" id="servicio-descripcion-field" data-th-classappend="${#fields.hasErrors('descripcion')}? 'has-error has-feedback'" data-th-class="form-group">
<label for="descripcion" class="col-md-3 control-label" data-th-text="#{label_servicio_descripcion}">descripcion</label>
<div class="col-md-6">
<input id="descripcion" name="descripcion" data-th-value="*{{descripcion}}" type="text" class="form-control" placeholder="descripcion" data-th-placeholder="#{label_servicio_descripcion}" data-toggle="tooltip" aria-describedby="descripcionStatus" />
<span data-th-classappend="${#fields.hasErrors('descripcion')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('descripcion')}" aria-hidden="true"></span>
<span id="descripcion-error" class="help-block" data-th-if="${#fields.hasErrors('descripcion')}" data-th-errors="*{descripcion}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="54220f01" id="servicio-logo-field" data-th-classappend="${#fields.hasErrors('logo')}? 'has-error has-feedback'" data-th-class="form-group">
<label for="logo" class="col-md-3 control-label" data-th-text="#{label_servicio_logo}">logo</label>
<div class="col-md-3">
<input id="logo" name="logo" data-th-value="*{{logo}}" type="text" class="form-control inputmask" placeholder="logo" data-th-placeholder="#{label_servicio_logo}" data-toggle="tooltip" aria-describedby="logoStatus" data-inputmask-alias="numeric" data-inputmask-digits="2" />
<span data-th-classappend="${#fields.hasErrors('logo')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('logo')}" aria-hidden="true"></span>
<span id="logo-error" class="help-block" data-th-if="${#fields.hasErrors('logo')}" data-th-errors="*{logo}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="f1acb8e1" id="servicio-telefono-field" data-th-classappend="${#fields.hasErrors('telefono')}? 'has-error has-feedback'" data-th-class="form-group">
<label for="telefono" class="col-md-3 control-label" data-th-text="#{label_servicio_telefono}">telefono</label>
<div class="col-md-6">
<input id="telefono" name="telefono" data-th-value="*{{telefono}}" type="text" class="form-control" placeholder="telefono" data-th-placeholder="#{label_servicio_telefono}" data-toggle="tooltip" aria-describedby="telefonoStatus" required="required" />
<span data-th-classappend="${#fields.hasErrors('telefono')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('telefono')}" aria-hidden="true"></span>
<span id="telefono-error" class="help-block" data-th-if="${#fields.hasErrors('telefono')}" data-th-errors="*{telefono}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="3c00987d" id="servicio-localidad-field" data-th-classappend="${#fields.hasErrors('localidad')}? 'has-error has-feedback'" data-th-class="form-group" data-th-with="collectionLink=${@linkBuilder.of('LocalidadsCollectionThymeleafController')}">
<label for="localidad" class="col-md-3 control-label" data-th-text="#{label_servicio_localidad}">Localidad</label>
<div class="col-md-6">
<!-- Select2 -->
<select data-th-field="*{localidad}" class="form-control dropdown-select-ajax" data-allow-clear="true" data-data-ajax--url="${collectionLink.to('select2')}" data-ajax--cache="true" data-ajax--delay="250" data-ajax--data-type="json" data-data-placeholder="#{info_select_an_option}">
<option data-th-unless="*{localidad} == null" data-th-value="*{localidad.id}" data-th-text="*{{localidad}}" selected="selected">Localidad</option>
</select>
<span data-th-classappend="${#fields.hasErrors('localidad')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('localidad')}" aria-hidden="true"></span>
<span id="localidad-error" class="help-block" data-th-if="${#fields.hasErrors('localidad')}" data-th-errors="*{localidad}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="19c21a81" id="servicio-disponibilidad-field" data-th-classappend="${#fields.hasErrors('disponibilidad')}? 'has-error has-feedback'" data-th-class="form-group" data-th-with="collectionLink=${@linkBuilder.of('DisponibilidadsCollectionThymeleafController')}">
<label for="disponibilidad" class="col-md-3 control-label" data-th-text="#{label_servicio_disponibilidad}">Disponibilidad</label>
<div class="col-md-6">
<!-- Select2 -->
<select data-th-field="*{disponibilidad}" class="form-control dropdown-select-ajax" data-allow-clear="true" data-data-ajax--url="${collectionLink.to('select2')}" data-ajax--cache="true" data-ajax--delay="250" data-ajax--data-type="json" data-data-placeholder="#{info_select_an_option}">
<option data-th-unless="*{disponibilidad} == null" data-th-value="*{disponibilidad.id}" data-th-text="*{{disponibilidad}}" selected="selected">Disponibilidad</option>
</select>
<span data-th-classappend="${#fields.hasErrors('disponibilidad')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('disponibilidad')}" aria-hidden="true"></span>
<span id="disponibilidad-error" class="help-block" data-th-if="${#fields.hasErrors('disponibilidad')}" data-th-errors="*{disponibilidad}">Error message.</span>
</div>
</div>
<div class="form-group has-error has-feedback" data-z="1d95a73d" id="servicio-categoria-field" data-th-classappend="${#fields.hasErrors('categoria')}? 'has-error has-feedback'" data-th-class="form-group" data-th-with="collectionLink=${@linkBuilder.of('CategoriasCollectionThymeleafController')}">
<label for="categoria" class="col-md-3 control-label" data-th-text="#{label_servicio_categoria}">Categoria</label>
<div class="col-md-6">
<!-- Select2 -->
<select data-th-field="*{categoria}" class="form-control dropdown-select-ajax" data-allow-clear="true" data-data-ajax--url="${collectionLink.to('select2')}" data-ajax--cache="true" data-ajax--delay="250" data-ajax--data-type="json" data-data-placeholder="#{info_select_an_option}">
<option data-th-unless="*{categoria} == null" data-th-value="*{categoria.id}" data-th-text="*{{categoria}}" selected="selected">Categoria</option>
</select>
<span data-th-classappend="${#fields.hasErrors('categoria')}? 'glyphicon glyphicon-remove form-control-feedback'" class="glyphicon glyphicon-remove form-control-feedback" data-th-if="${#fields.hasErrors('categoria')}" aria-hidden="true"></span>
<span id="categoria-error" class="help-block" data-th-if="${#fields.hasErrors('categoria')}" data-th-errors="*{categoria}">Error message.</span>
</div>
</div>
</fieldset>
<!-- buttons form -->
<div class="form-group">
<div class="col-md-9 col-md-offset-3">
<button type="submit" class="btn btn-primary" data-th-text="#{label_save}">Save</button>
<button type="reset" class="btn btn-default" onclick="window.history.back()" data-th-text="#{label_reset}">Cancel</button>
</div>
</div>
</form>
<!-- /FORM -->
</div>
</section>
<!-- /CONTENT -->
</div>
<!-- /CONTAINER -->
<footer class="container">
<!-- Content replaced by layout of the page displayed -->
</footer>
<!-- JavaScript
================================================== -->
<!-- Placed at the end of the document so that the pages load faster -->
<!-- JavaScript loaded by layout of the page displayed -->
<!--
Only the inner content of the following tag "javascript" is included
within the template, in the div "javascript"
-->
<div data-layout-fragment="javascript">
<!-- DateTimePicker -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.4/build/jquery.datetimepicker.full.min.js" data-th-src="@{/webjars/datetimepicker/build/jquery.datetimepicker.full.min.js}"></script>
<script src="../../static/public/js/datetimepicker-defaults.js" data-th-src="@{/public/js/datetimepicker-defaults.js}"></script>
<!-- jquery.inputmask -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.inputmask/3.3.1/jquery.inputmask.bundle.min.js" data-th-src="@{/webjars/jquery.inputmask/min/jquery.inputmask.bundle.min.js}"></script>
<script type="text/javascript" data-th-inline="javascript">
(function(jQuery) {
jQuery(document)
.ready(
function() {
Inputmask
.extendAliases({
'numeric' : {
'groupSeparator' : /*[[#{label_inputmask_groupSeparator}]]*/'.',
'radixPoint' : /*[[#{label_inputmask_radixPoint}]]*/','
},
'currency' : {
'prefix' : /*[[#{label_inputmask_prefix}]]*/'',
'suffix' : /*[[#{label_inputmask_suffix}]]*/' €'
}
});
});
})(jQuery);
</script>
<script src="../../static/public/js/inputmask-defaults.js" data-th-src="@{/public/js/inputmask-defaults.js}"></script>
<!-- JQuery Validation -->
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/jquery.validate.min.js" data-th-src="@{/webjars/jquery-validation/dist/jquery.validate.min.js}">
</script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/additional-methods.min.js" data-th-src="@{/webjars/jquery-validation/dist/additional-methods.min.js}">
</script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.15.0/localization/messages_es.js" data-th-src="@{/webjars/jquery-validation/src/localization/messages_}+${#locale.language}+'.js'" data-th-if="${#locale.language} != 'en'">
</script>
<script src="../../static/public/js/validation-defaults.js" data-th-src="@{/public/js/validation-defaults.js}">
</script>
<script type="text/javascript" data-th-inline="javascript">
(function(jQuery) {
jQuery(document)
.ready(
function() {
jQuery
.extend(
jQuery.validator.messages,
{
'dateformat' : /*[[#{error_invalid_date}]]*/'Please enter a correct date/time',
'inputmask' : /*[[#{error_invalid_maskValue}]]*/'Please enter a valid value',
});
});
})(jQuery);
</script>
</div>
</body>
</html>
Log.roo
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-06 20:50:24
project setup --topLevelPackage ar.edu.um.programacion2.oficios --java 8
jpa setup --database MYSQL --provider HIBERNATE --hostName 127.0.0.1 --databaseName oficiosdb --userName root
entity jpa --class ~.reference.Persona
field string --fieldName username --unique
field string --fieldName password --notNull
field string --fieldName email --unique
field string --fieldName telefono
field file --fieldName avatar --contentType PNG
entity jpa --class ~.domain.Prestador --extends ~.reference.Persona
field string --fieldName razonsocial --notNull
field string --fieldName oficio --notNull
entity jpa --class ~.reference.Disponibilidad
field string --fieldName franjahoraria --notNull
field string --fieldName descripcion
entity jpa --class ~.reference.Localidad
field string --fieldName nombre --notNull
field string --fieldName descripcion
entity jpa --class ~.reference.Categoria
field string --fieldName nombre --notNull
field string --fieldName descripcion
enum type --class ~.reference.TipoCalif
enum constant --name POSITIVO
enum constant --name NEGATIVO
enum constant --name NEUTRAL
entity jpa --class ~.domain.Cliente --extends ~.reference.Persona
field string --fieldName nombre --notNull
field string --fieldName apellido --notNull
field string --fieldName domicilio
field string --fieldName domicilio2
entity jpa --class ~.domain.Calificacion
field string --fieldName comentario --notNull
field enum --fieldName tipo --type ~.reference.TipoCalif
entity jpa --class ~.domain.CalificacionCliente --extends ~.domain.Calificacion
entity jpa --class ~.domain.Servicio
field string --fieldName nombre --notNull
field string --fieldName descripcion
field file --fieldName logo --contentType PNG
field string --fieldName telefono --notNull
field number --fieldName puntaje --type float
entity jpa --class ~.domain.CalificacionPrestador --extends ~.domain.Calificacion
repository jpa --all
finder add --name findByTelefono --entity ~.domain.Servicio
finder add --name findByNombreLike --entity ~.domain.Servicio
finder add --name findByPuntaje --entity ~.domain.Servicio
finder add --name findByUsername --entity ~.domain.Cliente
finder add --name findByUsername --entity ~.domain.Prestador
finder add --name findByEmail --entity ~.domain.Cliente
finder add --name findByEmail --entity ~.domain.Prestador
service --all
web mvc setup
web mvc view setup --type THYMELEAF
web mvc controller --all --responseType THYMELEAF
web mvc templates setup --type THYMELEAF
web mvc language --code es --useAsDefault
// script --file script_roo
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-06 21:19:16
help
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-07 09:03:07
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-07 20:12:48
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 01:34:17
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 01:34:37
web mvc finder --entity ~.domain.Servicio
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 02:28:28
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 02:28:44
web mvc finder --all
web mvc finder --all
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 02:29:31
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 02:29:39
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 02:29:54
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 02:30:11
hint
help
web mvc finder --all
web mvc finder --entity ~.domain.Cliente
web mvc finder --all
web mvc finder --all --responseType THYMELEAF
web mvc finder --entity ~.domain.Servicio --responseType THYMELEAF
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 03:13:33
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 03:14:23
hint
hint finders
finder add --entity ~.domain.Servicio --name findByCategoria
finder add --entity ~.domain.Servicio --name queryByCategoria
finder add --entity ~.reference.Categoria --name findByNombre
security setup --provider SPRINGLETS_JPA
entity jpa --class ~.domain.Administrador --extends ~.reference.Persona
web mvc controller --entity ~.domain.Administrador
service --entity ~.domain.Administrador
repository jpa --entity ~.domain.Administrador
service --entity ~.domain.Administrador
web mvc controller --entity ~.domain.Administrador
web mvc controller --entity ~.domain.Administrador --responseType THYMELEAF
finder add --entity ~.reference.Persona --name findByUsername
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-08 08:02:54
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-08 21:06:10
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-09 09:30:10
// Spring Roo 2.0.0.RC1 [rev 28015e3] log opened at 2017-03-09 10:08:32
// Spring Roo 2.0.0.RC1 [rev 28015e3] log closed at 2017-03-09 15:51:20
注意: 首先我认为 spring 安全问题导致用户没有列出该实体的权限,但是当我授予用户权限时问题从错误 403 更改为我现在的 500。 之后我完全卡住了。我尝试再次生成所有视图,但没有效果。
谢谢
在您最后评论了您在 Spring 安全配置 class 中遇到的问题以及在转换器注册时出现的错误,我知道您的问题出在哪里。
几周前,我在 Spring 安全性中检测到一个问题,并在他们的存储库中创建了以下问题:
https://github.com/spring-projects/spring-security/issues/4202
似乎如果 @Configuration
class 扩展了 WebSecurityConfigurerAdapter
抽象 class(就像在 Spring Roo 生成的代码中一样),某些组件是在 formatters
已在 Spring 上下文中注册之前尝试 @Autowired
一个 ConversionService
实例,因此 addFormatters
方法不包含任何格式化程序。
一个简单的变通方法可以解决您的问题,您将能够在您的项目中使用 Spring 安全性是 @Override
生成的 setContentNegotiationStrategy
方法=18=] class 不包含 @Autowired
注释。
下面的例子看一下如何正确覆盖这个方法。 (在此示例中,代码已注释)
如果这能解决您的问题,那么您 comment on the issue 说您也有同样的问题就太好了。
希望对您有所帮助,感谢您提供的所有信息!
您可以在此处找到 java 中的 Select2 与示例一起使用 Url:http://www.javasolution.in/search/label/autocomplete 您可以在此处找到完整代码和说明