我知道这里已经提出了类似的问题,但我相信我做了我的研究,尝试了很多不同的方法但是还没有运气。
我的配置:Spring Data JPA(hibernate,H2 DB),上面的REST层,并有一个AngularJS客户端发出请求。
REST路径:
@RequestMapping("/search/{destinationId}/{arrivalId}/{departureTime}/{arrivalTime}/{numberOfPassengers}")
public List<Flight> getFlightsWithCriteria(@PathVariable String destinationId,
@PathVariable String arrivalId,
@PathVariable String departureTime,
@PathVariable String arrivalTime,
@PathVariable Integer numberOfPassengers) { }
我按照以下方式调用该服务:
/search/2/1/2016-08-15T21:00:00.000Z/2016-08-15T21:00:00.000Z/2
顺便说一下,departureTime
对象在数据库上是TIMESTAMP
,测试数据的格式为2016-05-16 17:30:00.0
然后将日期解析为合适的格式以匹配DB:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date departureDate = sdf.parse(departureTime);
String formattedTime = dateFormat.format(departureDate);
然后在我的查询中使用此formattedTime参数,如下所示:
flights = (List<Flight>) entityManager
.createQuery("SELECT f FROM Flight f WHERE f.departureTerminal = :destination AND f.arrivalTerminal = :arrival AND f.departureTime <= :departureDate AND f.numberOfSeatsAvailable <= :numberOfPassengers")
.setParameter("destination", destination)
.setParameter("arrival", arrival)
.setParameter("departureDate", newDate)
.setParameter("numberOfPassengers", numberOfPassengers).getResultList();
然后我当然会收到:
java.lang.IllegalArgumentException: Parameter value [2] did not match expected type [java.lang.String (n/a)]
鉴于这些,您可能会说我为什么要将String
的查询发送到TIMESTAMP
对象,这是我迄今为止所尝试过的:
String
,Date
,Date
,TemporalType.TIMESTAMP
@DateFormat
@PathParam
String
并一次又一次地尝试..我已经在这个问题上抓了几个小时,但还没有解决方案。
请你看看我的代码并指出我做错了什么?
谢谢
答案 0 :(得分:0)
尝试通过在适当的位置添加括号来清除查询操作数的分组,以帮助您进行逻辑和调试,例如:以下
flights = (List<Flight>) entityManager
.createQuery("SELECT f FROM Flight f WHERE f.departureTerminal = :destination AND f.arrivalTerminal = :arrival AND (f.departureTime <= :departureDate) AND (f.numberOfSeatsAvailable <= :numberOfPassengers)")
.setParameter("destination", destination)
.setParameter("arrival", arrival)
.setParameter("departureDate", newDate)
.setParameter("numberOfPassengers", numberOfPassengers).getResultList();
只是另一个想法,尝试传递1参数然后调整您的请求服务1参数然后进入第二参数,等等。这将精确确定哪个参数有问题。
一旦你发现了罪魁祸首,现在通过传递唯一的请求参数来解决问题,将问题简化为该参数。
更新(我的解决方案):
我的代码有另一个破解,查询很好。我怀疑你输入的是像你报告的异常一样的问题。以下是我测试的内容,与您的查询类似,如果这可以帮助您进行测试。
<强> FlightTest.java 强>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { TestH2DatabaseConfiguration.class }, loader = AnnotationConfigContextLoader.class)
public class FlightTest extends AbstractTransactionalJUnit4SpringContextTests {
final static Logger log = LoggerFactory.getLogger(FlightTest.class);
@Autowired
@Qualifier("entityManagerFactory")
EntityManagerFactory entityManagerFactory;
@Test
@SuppressWarnings("unchecked")
public void test() throws ParseException {
assertNotNull(entityManagerFactory);
EntityManager entityManager = entityManagerFactory.createEntityManager();
assertNotNull(entityManager);
List<Flight> flights = (List<Flight>) entityManager.createQuery("FROM Flight").getResultList();
assertEquals(2, flights.size());
String departureTimeRequestInput = "2016-05-16T21:00:00.000Z";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Date departureDate = sdf.parse(departureTimeRequestInput);
Timestamp departureTimestamp = new Timestamp(departureDate.getTime());
flights = (List<Flight>) entityManager.createQuery(
"SELECT f FROM Flight f "
+ "WHERE "
+ "f.destinationId = :destinationId "
+ "and "
+ "f.arrivalId = :arrivalId "
+ "and "
+ "f.departureTime <= :departureDate "
+ "and "
+ "f.numberOfPassengers <= :numberOfPassengers")
.setParameter("destinationId", 1L)
.setParameter("arrivalId", 3L)
.setParameter("departureDate", departureTimestamp)
.setParameter("numberOfPassengers", 400L)
.getResultList();
assertEquals(1, flights.size());
log.debug("**H2**SIZE: " + flights.size());
}
}
<强> TestH2DatabaseConfiguration.java 强>
@Configuration
@EnableJpaRepositories("com.mycompany.h2.jpa")
@EnableTransactionManagement
public class TestH2DatabaseConfiguration {
final static Logger log = LoggerFactory.getLogger(TestH2DatabaseConfiguration.class);
@Bean
@Qualifier("dataSource")
public DataSource h2DataSource() {
return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).addScript("classpath:flight.sql").build();
}
@Bean
public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setDataSource(h2DataSource());
factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
factoryBean.setPackagesToScan("com.mycompany.h2.jpa");
factoryBean.setPersistenceUnitName("flight_table");
Properties ps = new Properties();
ps.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
ps.put("hibernate.show_sql", "true");
ps.put("hibernate.hbm2ddl.auto", "none");
factoryBean.setJpaProperties(ps);
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
}
<强> Flight.java 强>
public class Flight implements Serializable {
private static final long serialVersionUID = 2608721697556397731L;
@Id
private Long destinationId;
private Long arrivalId;
private Timestamp departureTime;
private Timestamp arrivalTime;
private Long numberOfPassengers;
...
}
<强> flight.sql 强>
CREATE TABLE flight (
destinationId INTEGER PRIMARY KEY,
arrivalId INTEGER,
departureTime TIMESTAMP,
arrivalTime TIMESTAMP,
numberOfPassengers INTEGER
);
INSERT INTO flight VALUES (1, 3, '2016-05-16 17:30:00.0', '2016-05-18 17:30:00.0', 400);
INSERT INTO flight VALUES (2, 2, '2016-05-17 17:30:00.0', '2016-05-19 17:30:00.0', 200);
<强>关键点:强> 这里的关键点是将用户输入时间超过java.sql.Timestamp对象,如 FlightTest.java 所示,例如
String departureTimeRequestInput = "2016-05-16T21:00:00.000Z";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Date departureDate = sdf.parse(departureTimeRequestInput);
Timestamp departureTimestamp = new Timestamp(departureDate.getTime());
和
...
.setParameter("departureDate", departureTimestamp)
...
Update2:以下交易中的示例航班对象插入
EntityManager entityManager = null;
try {
entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(flightObject);
entityManager.flush();
transaction.commit();
return flightObject;
}
finally {
entityManager.close();
}