我有一个名为user的实体,如下所示:
@Entity
@JsonSerialize(using = UserSerializer.class)
@Table(uniqueConstraints={@UniqueConstraint(columnNames = {"username"})})
public class User implements UserDetails {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, updatable = false)
private String username;
private String password;
@OneToOne(cascade={CascadeType.ALL})
@JoinColumn(name = "person_id")
private Person person;
@OneToOne(cascade={CascadeType.PERSIST})
@JoinColumn(name = "maintainer_id")
private Maintainer maintainer;
@ManyToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE}, fetch =
FetchType.EAGER)
@JoinTable(name = "user_role",
joinColumns = @JoinColumn(name = "user_id",
nullable = false, updatable = false),
inverseJoinColumns = @JoinColumn(name = "role_id",
nullable = false, updatable = false))
private Set<Role> roles;
public User() {
}
public User(String username, String password, Person person, Maintainer maintainer, Set<Role> roles) {
this.username = username;
this.password = password;
this.person = person;
this.maintainer = maintainer;
this.roles = roles;
}
// builder inner class omitted
// getters and setters omitted
// equals, hashCode and toString omitted
}
我还有一个用户摘要类,它旨在返回以进行分页和排序:
public class UserRow {
private Long id;
private String username;
private String firstName;
private String lastName;
private Set<Role> roles;
private String role;
private Long maintainerId;
private String maintainerName;
public static UserRow of(Long id, String username, String firstName, String lastName, Set<Role> roles, Long maintainerId, String maintainerName) {
UserRow userRow = new UserRow();
userRow.id = id;
userRow.username = username;
userRow.firstName = firstName;
userRow.lastName = lastName;
userRow.roles = roles;
userRow.maintainerId = maintainerId;
userRow.maintainerName = maintainerName;
return userRow;
}
// getters, setters, equals, hashCode and toString omitted
}
这与所有其他实体一起似乎在h2中很好地初始化,从控制台我看到如下内容:
create table user (
id bigint generated by default as identity,
password varchar(255),
username varchar(255),
maintainer_id bigint,
person_id bigint,
primary key (id)
)
和
create table user_role (
user_id bigint not null,
role_id bigint not null,
primary key (user_id, role_id)
)
甚至:
alter table user
add constraint UK_sb8bbouer5wak8vyiiy4pf2bx unique (username)
现在,我已经设置了控制器、服务和存储库...
控制器:
@Secured("ROLE_ADMIN")
@GetMapping(value = {"/users", "/users/maintainers/{mid}"}, produces = "application/json")
@ResponseStatus(value = HttpStatus.OK)
Response<List<User>> getPagedUsers(
@PathVariable("mid") Optional<Long> maintainerId,
@PageableDefault(page = DEFAULT_PAGE_NUMBER, size = DEFAULT_PAGE_SIZE)
@SortDefault.SortDefaults({
@SortDefault(sort = "username", direction = Sort.Direction.ASC),
@SortDefault(sort = "p.lastName", direction = Sort.Direction.ASC)
}) Pageable pageable) {
Page<UserRow> users;
if (maintainerId.isPresent()) {
users = userService.findSortedSummaryByMaintainer(maintainerId.get(), pageable);
} else {
users = userService.findSortedSummary(pageable);
}
return Response.of(users);
}
服务:公共接口UserService扩展了UserDetailsService{
Page<UserRow> findSortedSummary(Pageable pageable);
@Service
class UserServiceImpl implements UserService {
private static final Logger LOG = LoggerFactory.getLogger(UserService.class);
@Autowired
BCryptPasswordEncoder bCryptPasswordEncoder;
@Autowired
UserRepository userRepository;
@Autowired
RoleRepository roleRepository;
public Page<UserRow> findSortedSummary(Pageable pageable) {
Page<UserRow> userPage = userRepository.findSortedSummary(pageable.next());
userPage.forEach(us -> us.setRole(findMostPrivilegedRole(us.getRoles())));
return userPage;
}
}
}
存储库:公共界面UserRepository扩展了JpaRepository{
@Query(value = "select u.username, p.firstName, p.lastName, u.roles, m.id, m.name "
+ "from User u "
+ "inner join u.person p "
+ "inner join u.maintainer m",
countQuery = "select count(*) "
+ "from User u "
+ "inner join u.person p "
+ "inner join u.maintainer m",
nativeQuery = true)
Page<UserRow> findSortedSummary(Pageable pageable);
}
最后,我用以下方法来测试所有这些:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("embedded")
@AutoConfigureMockMvc
public class UserListControllerFunctionalTest {
@Autowired
private WebApplicationContext context;
@Autowired
private MockMvc mvc;
@Autowired
UserService userService;
List<User> franks;
@Before
public void setup() {
mvc = MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
franks = ModelFixtures.createFrankAndCohorts();
franks = userService.createAll(franks);
}
@Test
public void getListOfUsersWithRootSuccess() throws Exception {
mvc.perform(get("/api/users").header(AUTHORIZATION_HEADER, "Bearer " + ModelFixtures.ROOT_JWT_TOKEN))
.andDo(print())
.andExpect(status().isOk());
}
@After
public void tearDown() {
userService.deleteAll(franks);
}
}
所有的Spring安全材料都经过了广泛的测试和工作。
当测试调用控制器、服务和存储库时,我在存储库中遇到故障:
原因:组织。h2.jdbc。JdbcSQLException:未找到架构“U”;SQL语句:从用户u内部加入u.person p内部加入u.maintainer m order by u.username asc,p.lastName asc limit中选择u.username、p.firstName、p.lastName、u.roles、m.id、m.name?抵消[90079-197]组织。h2.消息。数据库异常。位于org的getJdbcSQLException(DbException.java:357)。h2.消息。数据库异常。get(DbException.java:179)位于org。h2.消息。数据库异常。get(DbException.java:155)
到目前为止,我发现将“User”这样的表与“u”这样的字母混叠是可以的,h2(和MySQL)中用户的内部表是“users”,因此“User”没有保留。所以我看不出这里有什么问题。有人能帮忙吗?
相关依存关系:
| +--- org.hibernate:hibernate-core:5.2.17.Final
| | +--- org.jboss.logging:jboss-logging:3.3.1.Final -> 3.3.2.Final
| | +--- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final
| | +--- org.javassist:javassist:3.22.0-GA
| | +--- antlr:antlr:2.7.7
| | +--- org.jboss:jandex:2.0.3.Final
| | +--- com.fasterxml:classmate:1.3.0 -> 1.3.4
| | +--- dom4j:dom4j:1.6.1
| | \--- org.hibernate.common:hibernate-commons-annotations:5.0.1.Final
| | \--- org.jboss.logging:jboss-logging:3.3.0.Final -> 3.3.2.Final
| +--- javax.transaction:javax.transaction-api:1.2
| +--- org.springframework.data:spring-data-jpa:2.0.7.RELEASE
| | +--- org.springframework.data:spring-data-commons:2.0.7.RELEASE
| | | +--- org.springframework:spring-core:5.0.6.RELEASE (*)
| | | +--- org.springframework:spring-beans:5.0.6.RELEASE (*)
| | | \--- org.slf4j:slf4j-api:1.7.25
| | +--- org.springframework:spring-orm:5.0.6.RELEASE
| | | +--- org.springframework:spring-beans:5.0.6.RELEASE (*)
| | | +--- org.springframework:spring-core:5.0.6.RELEASE (*)
| | | +--- org.springframework:spring-jdbc:5.0.6.RELEASE (*)
| | | \--- org.springframework:spring-tx:5.0.6.RELEASE (*)
| | +--- org.springframework:spring-context:5.0.6.RELEASE (*)
| | +--- org.springframework:spring-aop:5.0.6.RELEASE (*)
| | +--- org.springframework:spring-tx:5.0.6.RELEASE (*)
| | +--- org.springframework:spring-beans:5.0.6.RELEASE (*)
| | +--- org.springframework:spring-core:5.0.6.RELEASE (*)
| | \--- org.slf4j:slf4j-api:1.7.25
编辑-删除nativeQuery=true部分修复了“未找到模式”问题-本机查询必须表示按字面处理的所有元素。
然而,问题变成了:
Caused by:
org.h2.jdbc.JdbcSQLException: Syntax error in SQL statement "
SELECT
USER0_.USERNAME AS COL_0_0_,
PERSON1_.FIRST_NAME AS COL_1_0_,
PERSON1_.LAST_NAME AS COL_2_0_,
.[*] AS COL_3_0_,
MAINTAINER2_.ID AS COL_4_0_,
MAINTAINER2_.NAME AS COL_5_0_,
ROLE4_.ID AS ID1_17_,
ROLE4_.DESCRIPTION AS DESCRIPT2_17_,
ROLE4_.ROLE_NAME AS ROLE_NAM3_17_
FROM USER USER0_
INNER JOIN PERSON PERSON1_ ON USER0_.PERSON_ID=PERSON1_.ID
INNER JOIN MAINTAINER MAINTAINER2_ ON USER0_.MAINTAINER_ID=MAINTAINER2_.ID
INNER JOIN USER_ROLE ROLES3_ ON USER0_.ID=ROLES3_.USER_ID
INNER JOIN ROLE ROLE4_ ON ROLES3_.ROLE_ID=ROLE4_.ID
ORDER BY USER0_.USERNAME ASC, PERSON1_.LAST_NAME ASC LIMIT ? OFFSET ? ";
expected "*, NOT, EXISTS, INTERSECTS, SELECT, FROM, WITH";
不确定在这里“预期”的东西预期在哪里。。。
好的,我已经解决了。
这一切都在查询结构中。所以正确的jpql方法是:
@Query(value = "select new au.com.avmaint.api.access.model.UserRow(u.id, u.username, p.firstName, p.lastName, m.id, m.name) "
+ "from User u "
+ "inner join u.person p "
+ "inner join u.maintainer m",
countQuery = "select count(*) "
+ "from User u "
+ "inner join u.person p "
+ "inner join u.maintainer m")
Page<UserRow> findSortedSummary(Pageable pageable);
如果您打算返回一个非映射类(UserRow),那么您需要使用构造函数表示法。您也不能在SELECT子句中返回集合(user.roles),所以我必须在另一个查询中获取角色。这在服务层中很容易完成(请参阅forper
块中的第一行):
public Page<UserRow> findSortedSummary(Pageable pageable) {
Page<UserRow> userPage = userRepository.findSortedSummary(pageable.next());
userPage.forEach(row -> {
User user = userRepository.findById(row.getId()).orElseThrow(() -> new UsernameNotFoundException("User not found: " + row.getUsername()));
row.setRoles(user.getRoles());
row.setRole(findMostPrivilegedRole(user.getRoles()));
});
return userPage;
}
在这里,我使用了一个标准的Repository findById调用来按id返回单个用户并以这种方式获取角色。在单个查询中获取角色当然会很好,但JPQL只是没有那个级别的功能。
最后,我可能会说,除了最琐碎的领域示例(基本上是博客化的领域示例)之外,任何内容的分页和排序实际上都是相当棘手和复杂的。一旦我真正解决了这些问题,我会在博客上写一些真正有用的东西。
我创建了查询来根据日期间隔和房间类型搜索酒店的可用房间。当我运行此查询时,我得到以下错误: 组织。h2.jdbc。JdbcSQLException:未找到模式“R”;SQL语句: 有什么问题吗? 公共接口RoomRepository扩展JpaRepository{
我将Spring boot JPA实体定义为: 上述方法在DB2中效果良好,但在H2中效果不佳。 在application.properties,我有以下设置: 当我做maven的时候 原因:org。h2。jdbc。JdbcSQLSyntaxErrorException:未找到架构“MYSCHEMA”;SQL语句:公共类CarEntity实现可序列化的{。。。 我希望在H2上创建模式,因为我在我的
实现类 我正在尝试使用mockito为我的分页代码编写Junit测试用例,但它失败了,因为它期望方法的返回类型为Page.但是我返回客户列表。 我得到以下错误 如果您不确定为什么会出现上述错误,请继续阅读。由于语法的性质,可能会出现上述问题,因为: > 在错误编写的多线程测试中可能会发生此异常。有关并发测试的限制,请参阅莫基托常见问题解答。 间谍使用当(间谍.foo()).then()语法进行存根
在我的测试项目中,由于以下错误,Spring容器无法创建扩展JPararePository的bean。 原因:org.springframework.beans.factory.BeanCreationException:创建名为“sr svcInfomtrRepository”的bean时出错:FactoryBean在创建对象时引发异常;嵌套异常为java.lang.NosuchMethoder
我有3个实体在我的数据库。实体A具有主密钥PK-A,实体B具有主密钥PK-B,实体C具有主密钥PK-C。 实体A与实体B具有1对多关系,实体B与实体C具有1对多关系 我想在Spring Data JPA中基于PK-A(实际上是实体B中的外键)查询实体C。有可能吗? 但这行不通。还有什么建议我可以试试吗?
我想列一份订单,比如 这是我的密码 我使用的是Java Spring Boot和Spring Data JPA,我遇到了如下错误 你们能帮帮我吗!我想我在《findAllOrderBycreateDateDesc》中错了。谢谢对不起我的英语。这是我第一次发布我的问题。除息的