1, Analysis of data flow sequence when MyBatis is used
Requirements:
The front end submits the form and requests the background to use MyBatis to insert a piece of data into the database
Use process:
- The front end returns the data. At this time, the data is transferred to the corresponding method of the controller
- The controller calls the corresponding method of the service object to pass the data
- Service is actually an interface through which data is passed to the interface implementation class serviceImp of the service
- serviceImp receives the call, receives the data, and calls the corresponding method of userDAO object in this class to pass the data
- userDAO is actually an interface. It has a Mapper annotation on its head. It will pass data to its corresponding Mapper through this annotation
- Mapper.html has many names, but mapper has a namespace attribute, which locates the location of its corresponding DAO interface. userDAO also finds its own mapper according to this attribute
- There are many methods in a DAO interface, so it also needs to have corresponding implementation in its corresponding Mapper, that is, to complete the specific implementation of this method, such as adding, deleting, modifying and querying in the database
- Mapper has an id attribute whose value corresponds to the name of each method in DAO. DAO has multiple methods and mapper also has multiple id values
- After finding the corresponding Mapper, find the corresponding implementation according to the id, transfer the data to the implementation, and the implementation will complete the operation on the database according to the established rules
PS: this data flow actually uses the dependency inversion principle in the design pattern.
Dependency reversal principle:
- High level modules should not rely on low-level modules, but on their abstraction.
- Abstract should not rely on details, details should rely on abstraction
- The core of this principle is: interface oriented programming
- The design concept of this principle: the variability of relative details and the stability of abstract things;
An architecture based on abstraction is much more stable than an architecture based on detail - The purpose of using interfaces or abstract classes is to formulate specifications without involving any details,
Give the task of showing details to their implementation classes
2, Specific code (realizing registration function)
Directory structure:
regist.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>regist</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" type="text/css" href="css/style.css" /> </head> <body> <div id="wrap"> <div id="top_content"> <div id="header"> <div id="rightheader"> <p> 2009/11/20 <br /> </p> </div> <div id="topheader"> <h1 id="title"> <a href="#">main</a> </h1> </div> <div id="navigation"> </div> </div> <div id="content"> <p id="whereami"> </p> <h1> register </h1> <form action="login.html" method="post"> <table cellpadding="0" cellspacing="0" border="0" class="form_table"> <tr> <!--The whole is asynchronous communication, and the form is not submitted, so it is in the form input of name meaningless--> <td valign="middle" align="right"> user name: </td> <td valign="middle" align="left"> <!-- Bind form to Vue Attribute--> <input type="text" class="inputgri" v-model="user.username" /> </td> </tr> <tr> <td valign="middle" align="right"> Real name: </td> <td valign="middle" align="left"> <input type="text" class="inputgri" v-model="user.realName" /> </td> </tr> <tr> <td valign="middle" align="right"> password: </td> <td valign="middle" align="left"> <input type="password" class="inputgri" v-model="user.password" /> </td> </tr> <tr> <td valign="middle" align="right"> Gender: </td> <td valign="middle" align="left"> male <input type="radio" class="inputgri" v-model="user.sex" value="male" checked="checked"/> female <input type="radio" class="inputgri" v-model="user.sex" value="female"/> </td> </tr> <tr> <td valign="middle" align="right"> Verification Code: </td> <td valign="middle" align="left"> <input type="text" class="inputgri" v-model="code" /> </td> <td> <!--from Vue Get from url attribute--> <img id="num" :src="url"/> <!-- from Vue Called in the middle note getImage()Method of--> <a href="javascript:;" @click="getImage">Change one</a> </td> </tr> </table> <p> <input type="buttton" @click="register" class="button" value="Submit »" /> </p> </form> </div> </div> <div id="footer"> <div id="footer_bg"> ABC@126.com </div> </div> </div> </body> </html> <!--vue Import--> <script src="/ems_vue/js/vue.js"></script> <!--Asynchronous request import--> <script src="/ems_vue/js/axios.min.js"></script> <script> <!-- vue example--> var app = new Vue({ //Mount scope //From register As you can see from HTML, the whole is wrapped by wrap //So just pass in the scope wrap el:"#wrap", //Data obtained in scope data:{ //Define an attribute url to store the verification code data obtained from the back end //Let the page call this property to get the verification code image url:"", //user object user:{ sex:"male" }, //Verification Code code:"", }, methods:{ //Used to replace verification code getImage(){ this.getSrc(); }, //Get the verification code, reuse the code and make it easy to call getSrc(){ var _this = this; //console.log("xxxx"); //Asynchronous request: request verification code picture axios.get("http://localhost:8989/ems_vue/user/getImage?time="+Math.random()).then(res=>{ console.log(res.data); // Assign the image to the url attribute _this.url = res.data; }); }, //Used to register user information register(){ //this.code: it is equivalent to passing parameters in the address bar, so that UserController can directly get the code axios.post("http://localhost:8989/ems_vue/user/register?code="+this.code,this.user).then(res=>{ console.log(res.data); // Give the user a hint // true: the registration is successful. Do you want to jump to the page // false: registration failed if (res.data.state){ alert(res.data.msg+"Click OK to jump to the login page!"); location.href="http://localhost:8989/ems_vue/login.html" }else{ alert(res.data.msg); } }) } }, //Process before page creation //It is used to request for verification code before page creation created(){ //Get verification code this.getSrc(); } }) </script>
UserController:
package com.chen.controller; import com.chen.entity.User; import com.chen.service.UserService; import com.chen.utils.VerifyCodeUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.Base64Utils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** * @author light * @version 1.0 * @description * @create 2021-02-23 12:44 */ @Slf4j @RestController @CrossOrigin//Allow cross domain @RequestMapping("user") public class UserController { @Autowired //In fact, this is a tool object through which business methods are called //The business method is written in the implementation class of UserService interface: UserServiceImpl private UserService userService; /** * @description Process user login requests * <br> * @param * @return java.util.Map<java.lang.String, java.lang.Object> * @author light * @since 2021/2/23 21:39 */ @PostMapping("login") public Map<String, Object> login(@RequestBody User user){ log.info("Current login user information:[{}]",user.toString()); Map<String, Object> map = new HashMap<>(); try { User userDB = userService.login(user); map.put("state",true); map.put("msg","Login successful"); map.put("user",userDB); }catch (Exception e){ e.printStackTrace(); map.put("state", false); map.put("msg",e.getMessage()); } return map; } /* * Method for handling user registration * Return a registration information to the foreground * */ @PostMapping("register") // The purpose of using @ RequestBody is to directly encapsulate objects // When Axios transmits data, it is directly transmitted in the form of JSON string // You must use @ RequestBody to automatically convert it into the User object we want // HttpServletRequest: stores the last verification code information transmitted to the browser before public Map<String, Object> register( @RequestBody User user,String code, HttpServletRequest request){ log.info("User information:[{}]",user.toString()); log.info("Verification code entered by the user:[{}]",code); Map<String, Object> map = new HashMap<>(); try { String key = (String) request.getServletContext().getAttribute("code"); if(key.equalsIgnoreCase(code)){ //1. Call business method userService.register(user); map.put("state",true); map.put("msg","Prompt: Registration succeeded!"); }else{ throw new RuntimeException("Verification code exception"); } }catch (Exception e){ e.printStackTrace(); map.put("state",false); map.put("msg","Tips:"+e.getMessage()); } return map; } /** * @description Generate verification code image * <br> * @param request HttpServletRequest object * Requests on behalf of clients, * When the client accesses the server through HTTP protocol, * HTTP All the information in the request header is encapsulated in this object, * Through the method provided by this object, you can get all the information requested by the client. * @return java.lang.String * @author light * @since 2021/2/23 12:47 */ @GetMapping("getImage") public String getImageCode(HttpServletRequest request) throws IOException { //1. Use tool class to generate verification code String code = VerifyCodeUtils.generateVerifyCode(4); //2. Put the verification code into the scope of servletContext request.getServletContext().setAttribute("code",code); //3. Convert the picture to base64 //Byte array output stream creates a byte array buffer in memory, and all data sent to the output stream is saved in the byte array buffer. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); //Use the tool class to generate the verification code picture and put it into the byte array cache VerifyCodeUtils.outputImage(220,60,byteArrayOutputStream,code); //Use the tool class provided by spring to convert the verification code picture stream in the byte cache array into Base64 //And return to the browser return "data:image/png;base64," + Base64Utils.encodeToString(byteArrayOutputStream.toByteArray()); } }
UserService:
package com.chen.service; import com.chen.entity.User; public interface UserService { //User registration void register(User user); //User login User login(User user); }
UserServiceImp:
package com.chen.service; import com.chen.dao.UserDAO; import com.chen.entity.User; import com.chen.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.ObjectUtils; import java.util.Date; /** * @author light * @version 1.0 * @description * @create 2021-02-23 15:55 */ @Service @Transactional public class UserServiceImpl implements UserService { @Autowired // 1. This is also a tool object, which is used to call business methods // 2. The business method is actually written in usermapper In XML // 3. UserDAO through @ Mapper, usermapper XML connects the two through the direction of namespace // 4. UserMapper uses the attribute id to correspond to the methods of the UserDAO interface // 5. In fact, UserMapper is the method body of the method in UserDAO and the implementation of the method // 6. This is actually an embodiment of the design pattern (relying on the inversion principle) // ps: Dependency Inversion Principle: // 1. The high-level module should not rely on the low-level module, but on its abstraction. // 2. Abstraction should not rely on details, and details should rely on abstraction // 3. The core of this principle is: interface oriented programming // 4. The design concept of this principle: the variability of relative details and the stability of abstract things; // An architecture based on abstraction is much more stable than an architecture based on detail // 5. The purpose of using interfaces or abstract classes is to formulate specifications without involving any details, // Give the task of showing details to their implementation classes private UserDAO userDAO; @Override public void register(User user){ //0. Judge whether the user exists according to the user name entered by the user User userDB = userDAO.findByUserName(user.getUsername()); if(userDB == null){ //1. Generate user status user.setStatus("Activated"); //2. Set user registration time user.setRegisterTime(new Date()); //3. Call DAO userDAO.save(user); }else{ throw new RuntimeException("User name already exists!"); } } @Override public User login(User user) { // 1. Query according to the user name entered by the user User userDB = userDAO.findByUserName(user.getUsername()); if(!ObjectUtils.isEmpty(userDB)){ // 2. Compare passwords if(userDB.getPassword().equals(user.getPassword())){ return userDB; }else{ throw new RuntimeException("Password error"); } }else { throw new RuntimeException("User name input error"); } } }
UserDAO:
package com.chen.dao; import com.chen.entity.User; import org.apache.ibatis.annotations.Mapper; @Mapper //Create DAO object public interface UserDAO { void save(User user); User findByUserName(String username); }
UserMapper:
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.chen.dao.UserDAO"> <!-- save--> <!-- useGeneratedKeys="true"Assign the newly added primary key to the self-defined primary key keyProperty(id)in--> <insert id="save" parameterType="User" useGeneratedKeys="true" keyProperty="id"> insert into t_user values (#{id},#{username},#{realName},#{password},#{sex},#{status},#{registerTime}) </insert> <select id="findByUserName" parameterType="String" resultType="User"> select id, username,realname,password,sex,status,regsterTime from t_user where username=#{username} </select> </mapper>