1. 程式人生 > 實用技巧 >【平臺開發】— 6.從[登入]看前後端互動

【平臺開發】— 6.從[登入]看前後端互動

上次瞭解到了後端程式碼的大概分層,作用都是幹嘛的。那今天就結合著前端,一起看下它們是怎麼互動的。
其實簡單來講,就是前端把資料傳遞給後端,後端拿到資料後一通處理再返回給前端。

一、登入功能

前面提到的前端模板vue-admin-template,在本地run起來後,其實就可以看出一些端倪。
開啟登入頁後,按下F12,點選到network下,再點選登入按鈕。

可以看到有2個請求:

  • login
  • info

其中,login介面的返回中,有一個token值。
而在info介面的請求引數中,帶有這個token值。
這就是常見的登入了,後端驗證使用者名稱密碼是否存在,存在的話返回一個token值給使用者,那此使用者後面的請求都需要帶上這個token

值。

不過這個前端框架run起來裡的資料,都是通過mock模擬返回的,路徑如圖所示:

那其實一個道理,我在後端實現同樣的返回給前端處理不就可以了嘛?

二、登入-後端

根據前面講過的後端程式碼分層,我這裡直接貼上程式碼:

1.實體類User

@Entity
@Table(name = "user")
@JsonIgnoreProperties({"handler", "hibernateLazyInitializer"})
@Data
public class User {
    @Id //宣告一個欄位“id”為資料庫表的主鍵
    @GeneratedValue(strategy = GenerationType.AUTO) //標註主鍵的生成策略,通過strategy 屬性指定
    @Column(name = "id") //被標註欄位在資料庫表中所對應欄位的名稱
    private int id; //使用者id
    private String username; //使用者名稱稱
    private String password; //密碼
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date createTime; //建立時間
}

2.DAO類UserDAO

/**
 * UserDAO類繼承JpaRepository,就提供了CRUD和分頁 的各種常見功能。
 * JpaRepository<User, Integer>,引數分別是實體類,和這個實體類id的型別。
 */
public interface UserDAO extends JpaRepository<User, Integer> {

}

3.Service層UserService

這裡的isUserExist方法就是用來判斷輸入的使用者名稱密碼是否可以查詢到。
並且我在資料庫裡已經手動的插入了使用者名稱“admin”``密碼“111111”

的資料。

@Service //標記這是一個service類
public class UserService {
    @Autowired //自動裝配UserDAO物件
    UserDAO userDAO;

    /**
     * 判斷使用者是否存在,存在則返回true,不存在則返回false
     * @param username 使用者名稱
     * @param password 使用者密碼
     * @return true,false
     */
    public boolean isUserExist(String username, String password) {
        List<User> userList = userList();
        boolean isExist = false;
        for (User user: userList) {
            if (user.getUsername().equals(username) && user.getPassword().equals(password)) {
                isExist = true;
            }
        }
        return isExist;
    }
}

4.Controller類UserController

這裡就是呼叫了userService.isUserExist()判斷使用者是否在資料庫的user表裡.
存在的話,就返回一個code:20000 和一個寫死的tokenadmin-token;
不存在的話就返回code :50000和一個錯誤資訊“msg”

@RestController //標記這是控制器,下面每個方法的返回值都會直接轉換成json資料格式
@RequestMapping("user")
public class UserController {
    @Autowired //自動裝配 CategoryService
    UserService userService;

    @PostMapping("/login")
    public Map<String, Object> login(@RequestBody JSONObject data) throws Exception {
        String username = JSONPath.eval(data,"$.username").toString();
        String password = JSONPath.eval(data,"$.password").toString();
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> userToken = new HashMap<>();
        Map<String, Object> msg = new HashMap<>();
        if (userService.isUserExist(username, password)) {
            userToken.put("token","admin-token");
            result.put("code", 20000);
            result.put("data", userToken);
        } else {
            msg.put("msg", "使用者或密碼錯誤");
            result.put("code", 50000);
            result.put("data", msg);
        }
        return result;
    }

三、登入-前端

1. api目錄下的user.js

看過這個前端框架介紹你就知道了,要請求的後端API都是在這裡寫的,模組你自己分,好維護就行。
這裡我的後端介面url就是/my_platform/user/login。 這個介面請求要提交的引數是usernamepassword

import request from '@/utils/request'

export function login(username, password) {
  return request({
    url: '/my_platform/user/login',
    method: 'post',
    data: { // 提交的資料
      username,
      password
    }
  })
}

2. store目錄下的/modules/user.js

這裡程式碼比較多,我只貼改動的地方。那就是actions裡的login方法。
裡面的login方法就是呼叫了上面api模組下的login ,其他地方的程式碼暫時未動,以實現本章目標為主。

  login({ commit }, userInfo) { //定義 login 方法,在元件中使用 this.$store.dispatch() 呼叫
    const username = userInfo.username.trim()
    const password = userInfo.password
    return new Promise((resolve, reject) => {
      login(username, password).then(response => { //使用 login 介面進行網路請求
        const { data } = response
        commit('SET_TOKEN', data.token)
        setToken(data.token)
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  } 

3. views目錄下的/login/index.vue

上面template和下面style都沒動,中間script 是重點。
其中,我註釋掉了一些程式碼,因為這是專案裡demo用的演示,必須使用者名稱填admin。
但是我的目的是隻要是資料庫裡有的,就可以登入,所以不要這個前端驗證。

<script>
  import { validUsername } from '@/utils/validate'
  import { login } from '@/api/user'

  export default {
    name: 'Login',
    data() {
      // const validateUsername = (rule, value, callback) => {
      //   if (!validUsername(value)) {
      //     callback(new Error('Please enter the correct user name'))
      //   } else {
      //     callback()
      //   }
      // };
      // const validatePassword = (rule, value, callback) => {
      //   if (value.length < 6) {
      //     callback(new Error('The password can not be less than 6 digits'))
      //   } else {
      //     callback()
      //   }
      // };
      return {
        loginForm: {
          username: '',
          password: ''
        },
        // loginRules: {
        //   username: [{ required: true, trigger: 'blur', validator: validateUsername }],
        //   password: [{ required: true, trigger: 'blur', validator: validatePassword }]
        // },
        loading: false,
        passwordType: 'password',
        redirect: undefined
      }
    },
    watch: {
      $route: {
        handler: function(route) {
          this.redirect = route.query && route.query.redirect
        },
        immediate: true
      }
    },

    methods: {
      showPwd() {
        if (this.passwordType === 'password') {
          this.passwordType = ''
        } else {
          this.passwordType = 'password'
        }
        this.$nextTick(() => {
          this.$refs.password.focus()
        })
      },
      handleLogin() {
        this.$refs.loginForm.validate(valid => {
          if (valid) {
            this.loading = true
            this.$store.dispatch('user/login', this.loginForm).then(() => {
              this.$router.push({ path: this.redirect || '/' })
              this.loading = false
            }).catch(() => {
              this.loading = false
            })
          } else {
            console.log('error submit!!');
            return false
          }
        })
      }
    }
  }

</script>

handleLogin()就是對於登入的處理了, $store.dispatch會呼叫 /modules/user.js裡的login()

四、驗證登入功能

終於到了驗證時刻了,我已經在資料庫user表裡添加了其他使用者,所以我輸入正確的使用者名稱和密碼就可以登入。

登入成功。

當然了,不管是前端還是後端程式碼,我知道都埋了很多坑,也寫的不規範,但是目前處於初級階段,一步步來。
有錯誤的地方,也歡迎各位指出,謝謝!