我最近尝试在我的Web商店项目中实现Spring Security来区分单个用户。网站工作正常,除了一个问题我无法跟踪解决。我在User
类中有一个名为Customer
的对象。Customer
对象有id
、balance
等字段。而User
与Customer
具有OneToOne
关系,因此我可以使用单个对象作为凭据,并使用外键来指定用户细节-他的名字、姓氏、余额、拥有的产品等。
我也有Product
类,它和Customer
有ManyToOne
关系,它有自己的id
,productCost
等等。
我使用Spring MVC来处理正确的URL调度。当采取一些操作时,我使用@AuthenticationPrincipal
注解来获取当前记录的Customer
(通过User
中的外键),并修改与该外键链接的Customer
相关的数据。
当我通过控制器中的@AuthenticationPrincipal
修改Customer
数据时,更改是立即的,并且它们会显示在网站上。但是当我试图通过一些DAO修改数据时,例如,通过id
搜索Customer
,或者尝试从Product
getter获取拥有Product
的Customer
(ManyToOne
引用了所有Customer
),更改不会立即发生。数据库会立即并正确地更新自身,就像第一种情况一样,但是代码和网站状态中的集合不会改变直到我注销并再次登录-这是数据更新的时候。我怀疑这可能是由于更新UserDetails
直接为当前登录的用户更新数据的事实,但然后-我如何才能实现由id
找到的Customer
相同的效果?
代码片段:Users.java:
@Entity
@Table(name="users")
public class Users {
@Id
@Column(name="username")
private String username;
@Column(name="password")
private String password;
@Column(name="enabled")
private boolean isActive;
@OneToMany(mappedBy="user")
private Set<Authorities> authorities;
@OneToOne
@JoinColumn(name="customer_id")
private Customer customer;
Product.java:
@Entity
@Table(name="product")
public class Product {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private int id;
@Column(name="name")
private String productName;
@Column(name="description")
private String productDescription;
@Column(name="category")
private String productCategory;
@Column(name="cost")
private int productCost;
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="owner_id")
private Customer productOwner;
Customer.java:
@Entity
@Table(name="customer")
public class Customer {
//Class fields
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="id")
private int id;
@Column(name="balance")
private int balance;
@Column(name="first_name")
private String firstName;
@Column(name="last_name")
private String lastName;
@Column(name="email")
private String email;
@OneToMany(mappedBy="productOwner", fetch=FetchType.EAGER)
private List<Product> ownedProducts;
块控制器代码:
@Autowired
CustomerService customerService;
@Autowired
ProductService productService;
/*(...)*/
@GetMapping("/showOffer/{offerId}")
public String getOffer(@PathVariable int offerId, Model theModel, @AuthenticationPrincipal MyUserDetails user) {
Product retrievedProduct = productService.findById(offerId);
if (user.getCustomer().getBalance() >= retrievedProduct.getProductCost())
{
Customer retrievedProductOwner = retrievedProduct.getProductOwner();
/* This is where changes aren't applied immediately and I need to logout and login to process them. */
retrievedProductOwner.setBalance(1000);
/* This is where changes are immediately shown and Java collections are updated: */
user.getCustomer().setBalance(user.getCustomer().getBalance()-retrievedProduct.getProductCost());
/* Code below is an attempt to force immediate changes by updating collections directly from database - but that approach doesn't work */
productService.delete(retrievedProduct.getId());
retrievedProduct.getProductOwner().getOwnedProducts().clear();
retrievedProduct.getProductOwner().setOwnedProducts(productService.listOwnerProducts(retrievedProduct.getProductOwner()));
}
else {
System.out.println("Insufficient funds!");
}
return "redirect:/home";
TL:DR我在控制器中使用UserDetails
对象,并且我还在UserDetails
中使用Customer
的DAO作为外键。使用UserDetails
直接更新数据,一切正常,使用DAO直到我注销并登录后才进行更改。x1c 0d1x
2条答案
按热度按时间esbemjvw1#
据我所知,您的更改仅在您注销时提交。请尝试同步并在正确的时间提交任何修改,同时管理会话和事务会更安全,这样做时就不会出现任何不一致。然后告诉我结果。
kx7yvsdv2#
1.检查浏览器中的CTRL+F5(强制清除缓存)是否像注销和重新登录一样更新数据。如果是,则是缓存信息的问题。(这和(3)可能同时发生)
1.或者......或者是补充......您的数据提取请求可能会在数据库更新/提交操作完成之前被调用。如果是这样的话,如果您运行不同的更新和显示例程,这应该会变得很明显。例如,将A转换为B,然后转换为C,当您期望C...... A而不是B......等等时,您会得到类似B的结果。
1.最后,根据您设置后端的方式,您可能只填充一次用于前端的任何表单,而不是在每次访问该表单时动态查询数据库。