读书笔记《building-restful-web-services-with-spring-5-second-edition》票证管理-高级CRUD
假设我们有一个可供我们的客户 Peter 和 Kevin 使用的银行 Web 应用程序,并且我们的管理员 Sammy 和 CSR Chloe 可以在出现任何应用程序问题时提供帮助。
彼得和凯文在付款过程中面临一些问题。当他们尝试点击支付交易提交按钮时,它不起作用。此外,交易视图位于网页中。所以我们的用户(Peter 和 Kevin)将创建一张票来分享他们的问题。
创建工单后,客户/CSR/管理员可以对其进行更新。此外,客户可以删除自己的票。更新时,任何人都可以更改严重性;但是,只有 CSR 和 admin 可以更改状态,因为工单的状态与官方活动有关。
客户可以查看全部或单张票,但一次只能删除一张票。多重删除选项适用于 CSR 和管理员。但是,CSR 一次只能删除三张工单。管理员将完全控制工单管理应用程序,并且可以随时删除任意数量的工单。
让我们开始编写代码来满足上述要求。首先,我们需要从客户、CSR 和管理员注册开始。由于这些用户具有不同的角色,我们将为每个用户赋予 不同的用户类型。
为了区分用户,我们提出了三种不同的用户类型,因此当他们访问我们的 REST API 时,他们的授权会有所不同。以下是三种不同的 user 类型:
名称 |
用户类型 |
一般用户/客户 |
1 |
企业社会责任 |
2 |
行政 |
3 |
在我们之前的 User
类中,我们只有 userid
和 username
。我们可能还需要两个变量来满足我们之前提到的业务需求。我们将 password
和 usertype
添加到我们现有的 User
类中:
在前面的代码中,我们刚刚添加了 password
和 usertype
。此外,我们还为变量添加了 getter 和 setter 方法。
Note
您可以在我们的 GitHub 存储库 (https://github.com/PacktPublishing/Building-RESTful-Web-Services-with-Spring-5-Second-Edition) .你可能厌倦了添加 getter 和 setter 方法,所以我们将用 Lombok 库替换它们,我们将在本章后面讨论。但是,Lombok 库与 Eclipse 或 STS IDE 存在一些冲突问题,您可能需要注意这些问题。在这些 IDE 的某些版本中,由于 Lombok 库问题,您不会在创建类时获得预期的行为。此外,一些开发人员提到他们在使用 Lombok 时存在部署问题。
为了从我们的 User
类自动生成用户 ID,我们将使用一个单独的计数器。我们将保留一个静态变量来做到这一点;在实际应用中不建议保留静态计数器。为了简化我们的实现逻辑,我们使用了静态计数器。
以下代码将添加到我们的 User
类中:
我们从 100
个用户开始。每当添加新用户时,它会自动增加 userid
并将其分配给新用户。
现在我们将创建一个新的构造函数来将用户添加到我们的应用程序中。此外,我们将增加 usercounter
参数并将其分配为每个新用户的 userid
:
前面的构造函数将填充所有用户详细信息,包括 userid
(来自 usercounter
)。
在这里,我们将使用 username
、password
和 usertype
添加一个新用户> UserServiceImpl
类中; usertype
会因每个用户而异(例如,usertype
for admin 是 3
):
现在是添加客户的时候了。新客户将必须通过添加用户名和密码详细信息来创建帐户。
我们将讨论客户注册 API。此 API 将帮助任何新客户在我们这里注册他们的帐户:
在前面的代码中,我们添加了一个 API 来注册客户。调用此 API 的人将被视为客户(而非管理员/CSR)。如您所见,我们提到了 1
作为 usertype
,因此将其视为客户。
这是用于客户注册的 SoapUI 的屏幕截图:
此外,在前面的代码中,我们使用了 Util
类中的 getSuccessResult
。我们将看到其他 Util
方法,如下代码所示:
在前面的代码中,我们创建了一个 Util
类来保存将在不同控制器中使用的通用方法,例如 Ticket
和用户
。这些 Util
方法用于避免我们的应用程序中的代码重复。
在上一节中,我们介绍了用户注册主题,例如客户、管理员和 CSR。用户成功注册后,他们必须登录才能执行操作。因此,让我们创建与登录和会话相关的 API 和业务实现。
在转到登录和会话之前,我们将讨论一下JSON Web Token,它将被使用 用于会话身份验证。由于我们的 securityService
类中已经有了 createToken
方法,我们将只讨论 令牌生成中使用的主题
。
我们可能需要将 JSON Web Token 用于会话目的。我们将使用我们现有的令牌生成方法来保存我们的用户详细信息:
我们使用 user.getUserid()+"="+user.getUsertype()
作为主题。此外,我们提到了 15
分钟作为到期时间,因此令牌将仅在 15
分钟内有效。
让我们为客户创建一个登录 API。 customer 必须提供用户名和密码 详细信息作为参数。在实际应用程序中,这些详细信息可能来自 HTML 表单,如下所示:
在前面的代码中,我们通过传递所有必要的参数从 userService
调用了 getUser
方法。由于用户类型是 1
,我们在方法中传递了 1
。一旦我们得到用户,我们就检查它是否为空。如果为 null,我们将简单地抛出错误。如果用户不为空,我们创建一个令牌主题(user.getUserid()+"="+user.getUsertype()
)并使用 15
分钟到期时间。
如果一切顺利,我们将创建一个结果映射并将该映射作为 API 响应返回。当我们调用此 API 时,此地图将在我们的结果中显示为 JSON 响应。
另外,在前面的代码中,我们使用了 getUserNotAvailableError
来返回错误详情。由于我们将在所有与会话相关的 API 中使用此错误,因此我们创建了一个单独的方法来避免代码重复。
在这里,我们可以看到客户登录SoapUI的截图:
为了创建票证,我们需要创建一个 Ticket
类并将票证存储在列表中。我们会多讲Ticket
类,ticket list,以及其他ticket相关的工作,比如user Ticket管理、admin工单管理、CSR工单管理。
我们将创建一个 Ticket
类,其中包含一些 basic 变量来存储所有details 与票证相关。下面的代码将帮助我们理解 Ticket
类:
上述代码将存储工单详细信息,例如 ticketid
、creatorid
、createdat
、content
、严重性
和status
。此外,我们使用了一个名为 ticketCounter
的静态计数器来在创建票证时增加 ticketid
。默认情况下,它将以 300
开头。
此外,我们使用了构造函数和 toString
方法,因为我们将在实现中使用它们。
我们必须为所有与票证相关的业务逻辑实现创建 TicketService
接口(用于抽象方法)和 TicketServiceImpl
具体类.
以下代码将显示如何添加票证:
在前面的代码片段中,我们只是使用构造函数创建了一张票并将票添加到我们的列表中。我们可以清楚地看到,我们没有使用 Ticket
类中的增量器创建的 ticketid
。创建工单后,我们将其添加到工单列表中,该工单列表将用于其他操作。
对于所有与工单相关的操作,我们需要 用户会话。在 login 方法中,我们在登录成功后得到了 token。我们可以使用 token 来获取用户的详细信息。如果令牌不可用、不匹配或过期,我们将无法获取用户详细信息。
在这里,我们将实现从令牌中获取用户详细信息的方法:
在前面的代码中,我们使用了令牌来获取用户详细信息。我们使用 JWT 解析器首先获取声明,然后我们将获取主题。如果您还记得,当我们为所有用户登录选项创建令牌时,我们使用了 user.getUserid()+"="+user.getUsertype()
作为主题。因此主题将采用相同的格式,例如,101
(user ID)=1
(user type)客户,因为客户的用户类型是 1
。
此外,我们使用 subject.split("=").length != 2
检查主题是否有效。如果我们使用不同的令牌,它将简单地返回 null。
一旦我们得到正确的主题,我们将获得 userid
和 usertype
,然后我们将通过创建一个 <代码类="literal">用户 对象。
首先,为了简化我们的业务需求,我们保留只有客户才能创建工单的规则。管理员和 CSR 都不能创建工单。在实时情况下,您可能有不同的工单管理方法。但是,我们会尽量简化业务要求。
当用户提交工单时,他们只会发送有关他们在应用程序中遇到的问题的详细信息。我们为此类详细信息提供了 content 变量。此外,我们从他们在标头中传递的令牌中获取用户详细信息。
我们可以在以下屏幕截图中看到成功响应:
在之前的 API 中,我们使用了 @UserTokenRequired
注解来验证用户令牌。我们将在此处检查注释和实现的详细信息。
此类将在解密后检查用户 ID 和用户类型 validation 的用户令牌:
在前面的 UserTokenRequiredAspect
类中,我们刚刚从 header 中获取了 token 并验证了 token 是否有效。如果令牌无效,我们将抛出异常。
如果用户为 null(可能存在错误或空标记),它将在响应中返回 "User Not Available"
。一旦提供了必要的令牌,我们将通过调用前面提到的 TicketServiceImpl
中的 addTicket
方法添加票证。
Note
严重程度如下:
- Minor: Level 1
- Normal: Level 2
- Major: Level 3
- Critical: Level 4
1 级被认为是低级,4 级被认为是高级,如此处所示@SuppressWarnings ("unchecked")
。在某些地方,我们可能使用了 @SuppressWarnings
注释,我们需要告诉编译器它不需要担心正确的转换,因为它会被处理.
如果用户在任何与会话相关的 API 中传递了错误的 JWT
,我们将得到错误,如下所示:
前面的错误只是提到 JWT
字符串为空或 null。
与查看所有客户工单一样,客户也可以通过调用/{ticketid}
API。让我们看看他的方法是如何工作的:
在前面的 API 中,在验证了会话之后,我们使用了 TicketServiceImpl
中的 getTicket
方法来获取用户票的详细信息。
您可以借助此屏幕截图验证结果:
您可以清楚地看到我们的标头中使用了令牌。如果没有令牌,API 将抛出异常,因为它是与会话相关的事务。
在上一节中,我们看到了客户管理的 Ticket。客户可以单独控制他们的票,不能对其他客户的票做任何事情。在管理员模式下,我们可以控制应用程序中可用的任何票证。在本节中,我们将看到由管理员完成的工单管理。
由于管理员有 full 控件来查看应用程序中的所有工单,因此我们在 TicketServiceImpl
类没有任何限制。
在工单控制器 API 中,我们将为管理员添加一个获取所有 工单 的方法:
当管理员需要查看所有工单时,会调用上述 API,/by/admin
。我们在 TicketServiceImpl
类中调用了 getAllTickets
方法。
我们使用了一个简单的 AOP 来验证名为 @AdminTokenRequired
的管理令牌。让我们看看这个 API 的实现部分。
创建票证后, 管理员可以查看它。与客户不同,管理员除了其内容外,还可以更好地控制更新工单状态和严重性。
在前面的代码中,我们在 API 中使用了 /by/admin
路径来区分这个 API 和客户的更新方法。此外,我们从请求中获取严重性和状态参数。一旦管理员通过令牌验证,我们将调用 updateTicket
方法。如果你看到这个 updateTicket
方法,我们没有硬编码任何东西。
更新过程完成后,我们返回结果 "success"
作为响应,您可以在屏幕截图中查看:
最后,我们将在本节中讨论CSR Ticket 管理。 CSR 可能没有像管理员这样的控制;但是,在大多数情况下,他们可以选择在票务管理应用程序中匹配管理员。在下一节中,我们将讨论所有 CSR 授权的工单上的 CRUD 操作。
在本节中,我们将讨论通过 CSR 在工单管理中使用新内容、严重性和状态更新工单:
在前面的代码中,我们获取了所有必要的信息,例如内容、严重性和状态,并将这些信息提供给 updateTicket
方法。
我们使用了一个简单的 AOP 来验证名为 @CSRTokenRequired
的管理令牌。我们来看看这个 API 的实现部分。