78. Remove the comment – persistence layer
(a) Plan the SQL statements to be executed
SQL statements that need to be executed are as follows:
delete from comment where id=?
Copy the code
Before adding, deleting, or modifying data, you need to check whether the data being operated exists, whether you have permission to operate on the data, and other service rules that may exist.
The answer to whether the data exists can be found by querying:
select * from comment where id=?
Copy the code
With respect to permissions to manipulate data, you can temporarily design the business rule so that “the comment author, or any teacher, can delete the comment.” You can judge whether you are the comment publisher by the user_id in the query result and user_id in the login status. You can judge whether you are the teacher by the type attribute in the login status.
Usually, the conditions are very simple data operations can be directly completed by MyBatis Plus functions, you can not develop special related functions!
(b) Abstract methods of interfaces
There is no
(c) Configure SQL statements
There is no
(d) Unit testing
@SpringBootTest
@Slf4j
public class CommentsMapperTests {
@Autowired
CommentMapper mapper;
@Test
void deleteById(a) {
Integer id = 4;
int rows = mapper.deleteById(id);
log.debug("delete ok, rows={}", rows);
}
@Test
void selectById(a) {
Integer id = 4;
Comment comment = mapper.selectById(id);
log.debug("query ok, result={}", comment); }}Copy the code
79. Delete the comment – business layer
(a) Create an exception
Create exception “Comment data does not exist” :
public class CommentNotFoundException extends ServiceException {}
Copy the code
Create “insufficient permissions” exception:
public class PermissionDeniedException extends ServiceException {}
Copy the code
Failed to delete data exception:
public class DeleteException extends ServiceException {}
Copy the code
(b) Abstract methods of interfaces
/** * delete comments **@paramCommentId Indicates the ID * of the comment data@paramUserId Id of the current login user *@paramUserType Type of the current login user *@returnSuccessfully deleted comment data */
Comment delete(Integer commentId, Integer userId, Integer userType);
Copy the code
(c) Business realization
About business implementation steps:
public Comment delete(Integer commentId, Integer userId, Integer userType) {
// Call mapper.selectByid () with the commentId argument to query for information about deleted comments
// Check whether the query result is null
// Yes: This "comment" does not exist. Throw CommentNotFoundException
// Based on the userId in the query result and the parameter userId, determine whether the query result data belongs to the current login user.
// Based on the userType parameter, determine the identity of the current login user is "teacher",
/ / does not meet the, if the two conditions are not allowed to delete, throw PermissionDeniedException
Mapper.deletebyid () is called with the commentId argument to perform the deletion and get the number of affected rows returned
// Check whether the return value is not 1
// Yes: throws DeleteException
// Return the query result
}
Copy the code
Specific implementation business:
@Override
public Comment delete(Integer commentId, Integer userId, Integer userType) {
// Call mapper.selectByid () with the commentId argument to query for information about deleted comments
Comment comment = commentMapper.selectById(commentId);
// Check whether the query result is null
if (comment == null) {
// Yes: This "comment" does not exist. Throw CommentNotFoundException
throw new CommentNotFoundException("Failed to delete comment! Trying to access comment data does not exist!");
}
// Based on the userId in the query result and the parameter userId, determine whether the query result data belongs to the current login user.
// Based on the userType parameter, determine the identity of the current login user is "teacher",
// Note: To determine the userId, you must use equals()
// Use == or! = to determine data of type Integer, provided that the value range must be between -128 and 127
// For example, Integer i1 = 128; Integer i2 = 128;
// Use == to determine the above i1 and i2, the result will be false
if(! comment.getUserId().equals(userId) && userType ! = User.TYPE_TEACHER) {/ / does not meet the, if the two conditions are not allowed to delete, throw PermissionDeniedException
throw new PermissionDeniedException("Failed to delete comment! Only the publisher and teacher can delete this comment!");
}
Mapper.deletebyid () is called with the commentId argument to perform the deletion and get the number of affected rows returned
int rows = commentMapper.deleteById(commentId);
// Check whether the return value is not 1
if(rows ! =1) {
// Yes: throws DeleteException
throw new DeleteException("Failed to delete comment! Unknown error occurred while deleting, please contact system administrator!");
}
// Return the query result
return comment;
}
Copy the code
(d) Unit testing
@Test
void delete(a) {
try {
Integer commentId = 10;
Integer userId = 5;
Integer userType = User.TYPE_TEACHER;
Comment comment = service.delete(commentId, userId, userType);
log.debug("OK, comment >>> {}", comment);
} catch (ServiceException e) {
log.debug([Failed to delete comment]);
log.debug(Error type: {}, e.getClass().getName());
log.debug("Error: {}", e.getMessage()); }}Copy the code
80. Remove the comment – Controller layer
(a) Handling exceptions
You need to add the corresponding status code for each exception in R. state, and then handle the three exceptions created by the business layer in GloableExceptionHandler.
(b) Design request
Request path: / API /v1/comments/{commentId}/delete
Request parameters: @pathVariable (“commentId”) Integer commentId, @authenticationPriciple UserInfo UserInfo
Request type: POST
R
(c) Processing of requests
// http://localhost:8080/api/v1/comments/11/delete
@RequestMapping("/{commentId}/delete")
public R<Comment> delete(@PathVariable("commentId") Integer commentId,
@AuthenticationPrincipal UserInfo userInfo) {
Comment comment = commentService.delete(commentId, userInfo.getId(), userInfo.getType());
return R.ok(comment);
}
Copy the code
(d) Tests
http://localhost:8080/api/v1/comments/14/delete
81. Remove comments – front page
In Vue, if you need to traverse an array and need to get the index of each array element during traverse, you can:
v-for="(comment, index) in comments"
Copy the code
Comment in the above code is the data of the array element traversed, while index is the index of the array element. As specified in Vue 2.x, during traversal, the array element name and array index can be enclosed in parentheses on the left side of IN. The last name in parentheses is the array index, and the name can be customized!
After using the above code, you can use index to represent the subscript in the code area being traversed!
So, about traversing the entire comment list:
In the TAB of “Delete Comments” configure:
Then, in theanswers.js
Define a new function in:
After completing the above content, you can test the effect of clicking “delete” on the page, and if it is correct, you can continue to add the code for sending subsequent requests and processing results in the above function.
The complete code is as follows:
82. Modify the comment – persistence layer
(a) Plan the SQL statements to be executed
The SQL statement to modify a comment looks like this:
update comment set content=? where id=?
Copy the code
The above functions can be directly implemented using the updateById() method of MyBatis Plus.
In addition, before performing the modification, you should also perform a check on the modified data. The check logic can be the same as in delete.
(b) Abstract methods of interfaces
There is no
(c) Configure SQL statements
There is no
(d) Unit testing
@Test
void updateById(a) {
Comment comment = new Comment();
comment.setId(15);
comment.setContent("The functionality of the project is almost finished!!");
int rows = mapper.updateById(comment);
log.debug("update over. rows={}", rows);
}
Copy the code
83. Modify comments – Business layer
(a) Create an exception
To create a failed to modify data exception:
public class UpdateException extends ServiceException {}Copy the code
(b) Abstract methods of interfaces
/** * Modify comments **@paramCommentId Indicates the ID * of the comment data@paramContent The body of the comment@paramUserId Id of the current login user *@paramUserType Type of the current login user *@returnSuccessfully modified comment data */
Comment update(Integer commentId, String content, Integer userId, Integer userType);
Copy the code
(c) Business realization
About business implementation steps:
public Comment update(Integer commentId, String content, Integer userId, Integer type) {
// Call mapper.selectByid () with the commentId argument to query for information about edited comments
// Check whether the query result is null
// Yes: This "comment" does not exist. Throw CommentNotFoundException
// Based on the userId in the query result and the parameter userId, determine whether the query result data belongs to the current login user.
// Based on the userType parameter, determine the identity of the current login user is "teacher",
/ / does not meet the, if the two conditions are not allowed to delete, throw PermissionDeniedException
// Create a new Comment object
// Encapsulate commentId and Content in comment
// Call mapper.updateByid () based on comment to make the change and get the number of affected rows returned
// Check whether the return value is not 1
// If yes, UpdateException is thrown
// Encapsulate content in result
// Return the query result
}
Copy the code
Concrete implementation:
@Override
public Comment update(Integer commentId, String content, Integer userId, Integer userType) {
// Call mapper.selectByid () with the commentId argument to query for information about the modified comment
Comment result = commentMapper.selectById(commentId);
// Check whether the query result is null
if (result == null) {
// Yes: This "comment" does not exist. Throw CommentNotFoundException
throw new CommentNotFoundException("Failed to modify comment! Trying to access comment data does not exist!");
}
// Based on the userId in the query result and the parameter userId, determine whether the query result data belongs to the current login user.
// Based on the userType parameter, determine the identity of the current login user is "teacher",
if(! result.getUserId().equals(userId) && userType ! = User.TYPE_TEACHER) {/ / does not meet the, if the two conditions are not allowed to modify, sell PermissionDeniedException
throw new PermissionDeniedException("Failed to modify comment! Only the publisher and teacher can modify this comment!");
}
// Create a new Comment object
Comment comment = new Comment();
// Encapsulate commentId and Content in comment
comment.setId(commentId);
comment.setContent(content);
// Call mapper.updateByid () based on comment to make the change and get the number of affected rows returned
int rows = commentMapper.updateById(comment);
// Check whether the return value is not 1
if(rows ! =1) {
// If yes, UpdateException is thrown
throw new UpdateException("Failed to modify comment! Server busy, please try again later!");
}
// Encapsulate content in result
result.setContent(content);
// Return the query result
return result;
}
Copy the code
(d) Unit testing
@Test
void update(a) {
try {
Integer commentId = 12;
String content = "New Content!!!";
Integer userId = 12;
Integer userType = User.TYPE_STUDENT;
Comment comment = service.update(commentId, content, userId, userType);
log.debug("OK, comment >>> {}", comment);
} catch (ServiceException e) {
log.debug("Update comment failed");
log.debug(Error type: {}, e.getClass().getName());
log.debug("Error: {}", e.getMessage()); }}Copy the code
80. Modify the comment – controller layer
(a) Handling exceptions
UpdateException needs to be handled
(b) Design request
Request path: / API /v1/comments/{commentId}/update
Request parameters: @pathVariable (“commentId”) Integer commentId, String Content, @authenticationPrICIple UserInfo UserInfo
Request type: POST
R
(c) Processing of requests
// http://localhost:8080/api/v1/comments/11/update? content=Hello,Kafka!!!
@RequestMapping("/{commentId}/update")
public R<Comment> update(@PathVariable("commentId") Integer commentId,
String content,
@AuthenticationPrincipal UserInfo userInfo) {
Comment comment = commentService.update(commentId, content,
userInfo.getId(), userInfo.getType());
return R.ok(comment);
}
Copy the code
(d) Tests
http://localhost:8080/api/v1/comments/10/update?content=NewContent
81. Modify the comments – front page
In the comment list, each comment has its own form for modifying comments. By default, all comments are folded up. When you click “Edit”, it expands.
Since each entry in the comment list is traversed, the target of these edit links and the ID of the field in which each form is located are all the same, causing clicking on any edit to expand all forms and clicking on it again to collapse all forms! You must first adjust the ID of each edit linked directory and the field in which the form resides.
Adjustments to the area of the form:
[img-TBQL1C8P-1596299955578] [image-20200731152343997.png]
Then adjust the target location to which “Edit” links:
At this point, it should be normal to expand and collapse the form for modifying comments after clicking “Edit” on the page!
Next, set the default value in the form control so that the original comment body is displayed when expanded:
Then, assign an ID to the text field control to facilitate subsequent retrieval of the comment body filled in the text field:
Finally, we need a response function that submits the event for the form binding:
In answers.js, add a new function, first testing using:
Add $.ajax() to get commentId and content:
If you need to fold the form after successful modification, you can add it after successful publication (because you already bound the ID to the form area) :
$('#updateComment' + commentId).collapse('hide');
Copy the code
82. On “Adopting the Answer”
It is recommended to add static member internal interfaces to the Question class in advance:
public static interface Status {
String[] TEXTS = ["No reply"."To be resolved."."Resolved"];
int UNRESOLVED = 0;
int TO_BE_SOLVED = 1;
int RESOLVED = 2;
}
Copy the code
Do the same for the Answer class:
public static interface Status {
String[] TEXTS = {"Not adopted"."Accepted"};
int TO_BE_ACCEPT = 0;
int ACCEPTED = 1;
}
Copy the code
To “accept the answer”, you need to UPDATE the values of two tables:
- will
question
The tablestatus
The field value is updated toQuestion.Status.RESOLVED
; - will
answer
The tablestatus_of_accept
The field value is updated toAnswer.Status.ACCEPTED
.
At the business layer, @Transactional is used because two tables need to be updated at once.
If you are developing a simple version, you can update only the values of these two fields in the above two tables!
If you are developing a harder version, you can add a rule that “only one answer per question can be accepted, and once adopted, no one will be allowed to add answers or comments, edit or delete existing answers or comments.”
83. Architecture – Introduction to Kafka
When the client sends a request to the server, the server will use a multi-threaded way to handle requests from different clients! However, if you have a large number of clients and each client request takes a long time to be processed, you can have a large number of threads running on the server side at the same time, all processing data, and obviously a large amount of data in memory!
In fact, not all requests need to be handled urgently! For some requests, it may be possible to “synchronise” the requests to “queue” them, reducing the strain on the server!
The basic function of Kafka is to send and receive messages. When using Kafka, you can call Kafka directly to send a message when you receive a request from a client in the controller. Then, Kafka will receive the sent message, and then process it. Based on this mechanism, Kafka can also achieve some “notification”, “push” effect!
Before learning about Kafka, you should be familiar with some related concepts and terms:
Producer
Producer: Produces and sends messages;Consumer
: consumer: receives messages and processes them;Topic
: topic: used to classify messages;Record
: Record: Record of messages processed by queue transmission;Broker
: middleman: The host server that implements the data store and is also responsible for replicating messages when used in a cluster.
In terms of performance, Kafka is a bit like Tomcat. You only need to turn its service on. The program in the project can send messages to the Kafka server.
Examples of asynchronous queues similar to Kafka include RabbitMQ, ZeroMQ, RocketMQ, and more.
Huawei Cloud Download address:
- 2.5.0:mirrors.huaweicloud.com/apache/kafk…
- 2.4.1:mirrors.huaweicloud.com/apache/kafk…