Shimmer Market - セキュリティベースのユーザーログイン機能とユーザー登録機能 (バージョン 3.0)


記事ディレクトリ

セキュリティベースのユーザーログイン機能とユーザー登録機能

1 ユーザーログイン機能の実現 - ビルトインアカウントによるログイン

1.1 クライアント

PS:

  • SpringSecurity がリクエストを取得する方法getParameterは、このメソッドがfrom Date|| query Sting2 つしか取得できないことです。

  • ただ、今回フロントエンドが送ったリクエストはpay loadリクエストボディにパラメータを入れるリクエストであり、getParameterこのようなリクエストを取得することはできません。

    • 解決

      1. フロントエンド リクエストを from Date リクエストとして変更します
      2. バックエンドの受け入れ方法を変更する
    • ここでは、qs シリアライゼーションの最初の方法を使用して、ペイロードを fromDate リクエストに変換します。

1.1.1 Index.vue ページのログインと登録ボタン、およびログイン後の個人用ドロップダウン フォームとショッピング カート ボタンの実現

<el-header>
<div class="header-div">
   <div class="logo-div">
      <img:src="require('@/assets/logo.png')"style="width:440px;height:130px;border:0px solid red ;"/>     
   </div>
   <div class="personal-div">
      <div v-if="false">
          <el-button type="success" plain @click="$router.push('/login')">登录</el-butto
          <el-button type="warning" plain>注册</el-button>   
      </div>
      <div v-if="true">
        <el-dropdown>
              <el-button type="warning" icon="el-icon-user">
                      小明<i class="el-icon-arrow-down el-icon--right"></i>
              </el-button>
              <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人中心</el-dropdown-item>
              <el-dropdown-item>查看订单</el-dropdown-item>
              <el-dropdown-item>退出</el-dropdown-item>       
           </el-dropdown-menu>
        </el-dropdown>
        <el-badge :value="12" class="item">
             <el-button type="success" icon="el-icon-shopping-cart-full"  @click="$router.push('/showCar')">购物车</el-button>
              </el-badge>              
      </div>
    </div>    
</div>           
</el-header>

1.1.2 Login.vue ページの実装

  • ルーティングを構成する
import Login from "../views/Login.vue"
const routes = [
  {
    
    
    path: "/login",
    name: "login",
    component: Login,
  },
];
  • Login.vue ページの UI 表示
<template>
    <div class="win-logoin">
        <div class="container" id="login-container">
            <img :src="require('@/assets/logo.png')" style="width:440px;height:130px;border:0px solid red ;"/>
            <div class="form">
            <div class="login-input">
                <label>用户名:</label>
                <input type="text" v-model="user.username" />
            </div>
            <div class="login-input">
                <label>&nbsp;&nbsp;码:</label>
                <input type="password" v-model="user.password" />
            </div>
            <div class="login-button">
                <button @click.prevent="login">登录</button>
            </div>
            </div>
        </div>
    </div>
</template>

<script>
</script>
<style scoped>
.win-logoin {
      
      
    position: absolute;
    top: 0px;
    bottom: 0px;
    margin: 0px;
    left: 0px;
    right: 0px;
    padding: 0px;
    display: flex;
    background:url( "../assets/images/login/backgroundlogin.png");
    /*设置弹性布局*/
    flex-direction: row;
    /*设置水平方向*/
    justify-content: center;
    /*根据direction的方向设置居中*/
    align-items: center;
    /*根据direction的反方向设置居中*/
}

.container {
      
      
    width: 700px;
    height: 400px;
    border-radius: 5px;
    box-shadow: 0px 0px 10px 5px black;
    display: flex;
    background:url( "../assets/images/login/background.png");
    /*设置弹性布局*/
    flex-direction: column;
}

.form{
      
      
    margin-left: 28%;
}
.login-input {
      
      
    position: relative;
    width: 300px;
    height: 50px;
    border: 0px solid red;
    margin: 5px 0;
}

.login-input>label {
      
      
    box-sizing: border-box;
    position: absolute;
    border: 0px solid red;
    width: 80px;
    height: 50px;
    line-height: 50px;
    letter-spacing: 2px;
    padding-left: 10px;
    color: #666666;
}

.login-input>input {
      
      
    box-sizing: border-box;
    border-radius: 5px;
    border: 1px solid #dddddd;
    padding-left: 80px;
    outline: none;
    font-size: 18px;
    width: 100%;
    height: 100%;
}

.login-button {
      
      
    position: relative;
    width: 300px;
    height: 50px;
    margin: 15px 0;
}

.login-button>button {
      
      
    border: 0;
    width: 100%;
    height: 100%;
    border-radius: 5px;
    border: 1px solid #dddddd;
    outline: none;
    background-color: white;
    letter-spacing: 15px;
    padding-left: 15px;
    color: #666666;
    font-size: 18px;
}

.login-button>button:hover {
      
      
    cursor: pointer;
    background-color: cornflowerblue;
    color: white;
}

.login-button>button:active {
      
      
    font-weight: bold;
    outline: none;
    border: 0;
    box-shadow: 0px 0px 8px 1px #7088ff;
}
</style>

1.1.3 バックエンドへのデータ転送と対応処理

export default {
    
    
    name: "Login",
    data() {
    
    
        return {
    
    
            user: {
    
    },//当前登录的对象
        };
    },
    methods: {
    
    
        //登录方法
        login() {
    
    
            //加载条
            const loading =this.$loading({
    
    
                lock:true,
                text:"登陆中,请稍后",
                spinner:"el-icon-loading",
                background: "rgba(0,0,0,,0.7)"
            });
            this.$axios
                .post('login', this.$qs.stringify(this.user))
                .then(response=>{
    
    
                    loading.close();

                    let result=response.data;
                    if(result.success){
    
    
                        let curUser =result.data;
                        //弹出提示框
                         this.$swal.fire({
    
    
                            icon: 'success',
                            title: result.message,
                            showConfirmButton: false,
                            timer:1000,
                            didClose:()=>{
    
    
                                this.$router.push("/");
                            }
                        });
                    }else{
    
    
                        this.$swal.fire({
    
    
                            icon: 'error',
                            title: result.message,
                            showConfirmButton: false,
                            timer: 1000,
                            didClose: () => {
    
    
                                alert("弹窗已关闭");
                            }
                        });
                    }
                })
                .catch(error=>{
    
    
                    alert(error)
                })
        }
    }
};

1.2 サーバー

1.2.1 Spring Security 依存関係の紹介

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
</dependency>

1.2.2 Spring セキュリティの設定

  • プロセッサはコントローラよりも高い優先度で実行されます
/**
 * SpringSecurity配置类
 */
@Configuration
public class SecurityConfig {
    
    

    /**
     * 用于拦截请求,并对请求进行处理
     * @param httpSecurity
     * @return  SecurityFilterChain:Security过滤器链
     */
    @Bean
    @Autowired
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
    
    
        httpSecurity
                //security默认禁止跨域请求
                .cors()
             .and()
                .csrf().disable()//禁止跨域伪造访问
                .authorizeRequests()//获得请求
                    .antMatchers("/book/*")
                        .permitAll()//无需认证直接访问
                    .anyRequest()//所有请求
                         .authenticated()//必须认证才能访问
             .and()
                //配置登陆页form表单
                .formLogin()//配置表单
                    .loginProcessingUrl("/login")//使用重定向方式配置登陆处理器的url地址,该地址所对应处理类由SpringSecurity提供
                    .loginPage("http://localhost:8080/#/login")//配置登陆页
                    .successHandler(new LoginSuccessHandler())//成功处理器,成功后跳转到指定处理器
                    .failureHandler(new LoginFailureHandler())
        ;
        return httpSecurity.build();//获得securityFilterChain的实现类对象并返回
    }
}

1.2.3 ログイン成功ハンドラとログイン失敗ハンドラを追加する

  • ログイン失敗ハンドラー
/**
 * 登陆失败处理器,该处理器实现AuthenticationFailureHandler
 *  当用户登陆成功后会自动执行该处理器里的onAuthenticationFailure方法
 */
public class LoginFailureHandler implements AuthenticationFailureHandler {
    
    
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
    
    
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().println("失败");
    }
}
  • ログイン成功ハンドラー
/**
 * 登陆成功处理器,该处理器实现AuthenticationSuccessHandler
 *  当用户登陆成功后会自动执行该处理器里的onAuthenticationSuccess方法
 */
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    
    
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    
    
        //设置响应类型及编码集
        response.setContentType("application/json;charset=utf-8");
		response.getWriter().println("成功");
    }
}

2 ユーザーログイン機能の実装 - データベースベースのログイン

2.1 クライアント

2.1.1 ログイン成功後、バックエンドからユーザー情報を処理する

クライアントが sessionStorage を使用してスマート文字列を格納する場合、JSON.stringify()文字列に変換する必要があります

if(result.success){
    
    //登陆成功
    let curUser =result.data;
     //弹出提示框
     this.$swal.fire({
    
    
        icon: 'success',
        title: result.message,
        showConfirmButton: false,
        timer:1000,
        didClose:()=>{
    
    
            //将当前用户登陆者信息存入sessionStorage
            let curUser=result.data;
            let curUserInfo = JSON.stringify(curUser)
            window.sessionStorage.setItem("curUserInfo",curUserInfo);
            this.$router.push("/");
        }
    });
}

2.1.2 メインページに入った時の対処法

<div class="personal-div">
     <div v-if="curUserInfo ==null?true:false">
         <el-button type="success" plain @click="$router.push('/login')">登录</el-button>  
         <el-button type="warning" plain>注册</el-button>   
     </div>
     <div v-if="curUserInfo ==null?false:true">
             <el-dropdown>
                 <el-button type="warning" icon="el-icon-user">
                         {
   
   {curUserInfo.user_name}}
                     <i class="el-icon-arrow-down el-icon--right"></i>
                 </el-button>
                 <el-dropdown-menu slot="dropdown">
                 <el-dropdown-item>个人中心</el-dropdown-item>
                 <el-dropdown-item>查看订单</el-dropdown-item>
                 <el-dropdown-item>退出</el-dropdown-item>       
             </el-dropdown-menu>
         </el-dropdown>

         <el-badge :value="12" class="item">
                 <el-button type="success" icon="el-icon-shopping-cart-full"  @click="$router.push('/showCar')">购物车</el-button>
         </el-badge>              
     </div>
 </div>   

2.1.3 メイン ページからユーザー情報を取得する

    data(){
    
    
        return{
    
    
            curUserInfo:null,//用户信息
        }
    },
    methods: {
    
    
      //获取用户信息
      getCurUserInfo(){
    
    
        //从sessionStorage获取用户信息,并转化为Json形式
        this.curUserInfo= JSON.parse(window.sessionStorage.getItem("curUserInfo"));
      },
    created(){
    
    
        this.getCurUserInfo();
    }

2.2 サーバー

2.2.1 UserDetailsS​​ervice オブジェクトを宣言し、認証マネージャーに挿入する

ユーザー情報を認証ハンドラーに送信し、パスワードの暗号化を設定する

	@Autowired
    private UserDetailsService userDetailsService; 
   /**
     * 注入认证处理器
     * @param builder
     * @throws Exception
     */
    @Autowired
    public void registerProvider(AuthenticationManagerBuilder builder) throws Exception{
    
    
           builder.userDetailsService(userDetailsService)
                   .passwordEncoder(new BCryptPasswordEncoder());
    }

2.2.2 モデル-userInfo の作成

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo implements Serializable {
    
    
    private Integer user_id;
    private String user_name;
    private String user_password;
    private String user_email;
    private Date user_birthday;
    private String user_hobbys;
    private Integer user_sex;
    private String user_address;
    private Integer user_status;
}

2.2.3 UserMapper の作成

ユーザー名によるユーザー情報のクエリ

@Repository
public interface UserMapper {
    
    

    /**
     *
     * 根据用户名获得用户对象
     * @param username
     * @return
     */
    @Select("select * from tbl_user where user_name=#{username}")
    public UserInfo getUserByUsername(String username);
}

2.2.3 UserDetailsS​​ervice 実装クラスの作成 UserDetailsS​​erviceImpl

ユーザー情報を UserDetails オブジェクトにカプセル化します (UserDetails の実装クラス User がここで返されます (User はセキュリティによって提供されます))。

/**
 * 处理认证逻辑的类
 * + 该类需要重写接口中的loadUserByUsername方法根据用户名获得用户对象
 */
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    
    
    @Resource
    private UserMapper userMapper;

    /**
     * 1.根据用户名获得用户信息
     * 2.将用户信息认证需要的数据封装到UserDetails的实现类对象中(UserInfo)
     * 3.将封装好的认证信息提交给SpringSecurity进行认证
     *
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
    
        UserInfo userInfo = userMapper.queryUserByUserName(username);
        //设置当前账户权限集合
        //判断用户名是否正确
        if (userInfo == null) {
    
    //用户不存在
            return null;
        }
        if (userInfo.getUser_status() == -1) {
    
    //用户被冻结
            return null;
        }
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        User user = new User(
                userInfo.getUser_name(),
                userInfo.getUser_password(),
                true,//账户是否启用
                true,//账户是否过期
                true,//凭证是否过期
                userInfo.getUser_status() == 0 ? true : false,//账户是否被锁定
                authorities//账户拥有权限集合
        );
        return user;
    }
}

2.2.4 パブリック クラスの作成 - CurUserInfo

現在のユーザー情報を保存する

/**
 * 当前登陆用户对象
 * 存放当前用户信息
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CurUserInfo {
    
    
    private Integer user_id;
    private String user_name;
}

2.2.5 サービス層のユーザー オブジェクトの内容を変更する

List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
        //为保护密码信息,将密码取出来后设为null
        String password = userInfo.getUser_password();
        userInfo.setUser_password(null);
        User user = new User(
                JSONObject.toJSONString(userInfo),//将用户信息对象转化为json串存放到username中
                password,
                true,//账户是否启用
                true,//账户是否过期
                true,//凭证是否过期
                userInfo.getUser_status() == 0 ? true : false,//账户是否被锁定
                authorities//账户拥有权限集合
        );

2.2.6 ログインが成功するようにハンドラを変更する

public class LoginSuccessHandler implements AuthenticationSuccessHandler {
    
    
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    
    
        //设置响应类型及编码集
        response.setContentType("application/json;charset=utf-8");
        //获得认证对象获得认证主体,主体式User对象
        User user= (User) authentication.getPrincipal();
        //将用户名转化为UserInfo对象
        //user.getUsername存放有用户信息,将该信息转换为UserInfo对象
        UserInfo userInfo = JSONObject.parseObject(user.getUsername(), UserInfo.class);
        //将userInfo中的数据转存到CurUserInfo中
        CurUserInfo curUserInfo=new CurUserInfo();
        curUserInfo.setUser_id(userInfo.getUser_id());
        curUserInfo.setUser_name(userInfo.getUser_name());
        Result result =Result.success("登陆成功",curUserInfo);
        response.getWriter().println(JSONObject.toJSONString(result));
    }
}

3 ログイン失敗とログアウト機能

3.1 ログイン失敗時の処理

UsernameNotFoundException: ユーザー名が存在しないエラー (デフォルトでは無効)

BadCredentialsException:間違ったパスワード

LockedException:アカウントロックエラー

3.1.1 障害ハンドラーの扱い

/**
 * 登陆失败处理器,该处理器实现AuthenticationFailureHandler
 * 当用户登陆成功后会自动执行该处理器里的onAuthenticationFailure方法
 */
public class LoginFailureHandler implements AuthenticationFailureHandler {
    
    
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
    
    
        response.setContentType("application/json;charset=utf-8");
        String errMsg = "";
        if (exception.getClass() == UsernameNotFoundException.class) {
    
    
            errMsg = "用户名不存在";
        } else if (exception.getClass() == BadCredentialsException.class) {
    
    
            errMsg = "密码错误";
        } else if (exception.getClass() == LockedException.class) {
    
    
            errMsg = "账户被冻结";
        }
        System.out.println("ssssssssssssssssss");
        System.out.println(errMsg);
        //401:认证未通过
        response.getWriter().println(JSONObject.toJSONString(Result.fail(401, errMsg)));
    }
}

3.1.2 オープンUsernameNotFoundException例外

By default, the exception is AbstractUserDetailsAuthenticationProviderclosed. このクラスには、hideUserNotFoundExceptionsデフォルトで true に設定された属性があり、例外がクローズされていることを示します。

注:のサブクラスのサブクラスのDaoAuthenticationProvider場合AbstractUserDetailsAuthenticationProvider

  • 構成クラスのオーセンティケーター メソッドを変更する
/*
 * 注入认证处理器
 * @param builder
 * @throws Exception
 */
@Autowired
public void registerProvider(AuthenticationManagerBuilder builder) throws Exception{
    
    
    //创建认证处理器对象
    DaoAuthenticationProvider daoAuthenticationProvider =new DaoAuthenticationProvider();
    //开启该异常
    daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
    daoAuthenticationProvider.setUserDetailsService(userDetailsService);
    daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
    builder.authenticationProvider(daoAuthenticationProvider);//将该认证处理器交给SpringSecurity
            //如上配置后下面设置无效
       /*builder.userDetailsService(userDetailsService)
               .passwordEncoder(new BCryptPasswordEncoder());*/
}

3.2 口座からの出金の取り扱い

3.2.1 構成クラスの参加と終了の構成

.and()
    .logout()//退出配置
        .logoutUrl("/exit")//退出地址
        .invalidateHttpSession(true)//退出销毁session
        .logoutSuccessHandler(new LogoutSuccessHandlerImpl())//退出成功的处理器

3.2.2 成功した exit Handler の扱い

/**
 * 退出成功处理器,该处理器实现LogoutSuccessHandler
 *  当用户登陆成功后会自动执行该处理器里的onLogoutSuccess方法
 */
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
    
    
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
    
    
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().println(JSONObject.toJSONString(Result.success("退出成功!!!")));
    }
}

3.2.3 クライアント処理

  • ドロップダウンリスト追加イベント
<el-dropdown @command="handleCommand">
     <el-button type="warning" icon="el-icon-user">
           {
    
    {
    
    curUserInfo.user_name}}
			<i class="el-icon-arrow-down el-icon--right"></i>
     </el-button>
     <el-dropdown-menu slot="dropdown">
     <el-dropdown-item command="1">个人中心</el-dropdown-item>
     <el-dropdown-item command="2">查看订单</el-dropdown-item>
     <el-dropdown-item command="3">退出</el-dropdown-item>       
</el-dropdown-menu>
  • 対応するイベントを処理し、バックエンドに終了リクエストを発行します
handleCommand(command) {
    
    
     switch(command){
    
    
     case "1":
       alert("个人中心");
       break;
     case "2":
       alert("查看订单");
       break;
     case "3":
       this.$axios
           .delete("/exit")
           .then(response=>{
    
    
               let result =response.data;
               if(result.success){
    
    
                 //删除sessionStorage
                 window.sessionStorage.removeItem("curUserInfo");
                 //重置curUser
                 this.curUserInfo=null;
                  this.$notify.error({
    
    
                       title: result.message,
                       message: '退出成功',
                       duration: 300,
                   });
               }
           })
           .catch(error=>{
    
    
             alert(error)
           })
       break;               
     }
 }

4 ログに記録されていないアクセスの処理

4.1 axios リクエスト インターセプターを使用して、ログに記録されていないアクセスを処理する

4.1.1 Axios リクエストインターセプター

  • Axios は、バックエンドにアクセスせずにフロントエンドでリクエストを直接インターセプトするリクエスト インターセプターを提供します。
  • バックエンドの応答をインターセプトし、フロントエンドにはアクセスしない応答インターセプター
  • つまり、リクエストまたはレスポンスが処理されるthen前にインターセプトするcatch
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    
    
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    
    
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    
    
    // 对响应数据做点什么
    return response;
  }, function (error) {
    
    
    // 对响应错误做点什么
    return Promise.reject(error);
  });
  • 後でインターセプターを削除する場合は、次のようにします。
var myInterceptor = axios.interceptors.request.use(function () {
    
    /*...*/});
axios.interceptors.request.eject(myInterceptor);
  • カスタム axios インスタンスにインターセプターを追加できます
var instance = axios.create();
instance.interceptors.request.use(function () {
    
    /*...*/});

axiosキャンセルリクエスト

  • リクエスト自体をキャンセルすることはできません. axios の内部メソッドは、リクエストを失敗させ、リクエストを自分自身に戻すことですcatch.
  • 今度は同じものを使って複数のリクエストcancel tokenをキャンセルします

4.1.2 main.js でグローバル インターセプターを構成する

/**
 *添加请求拦截器
 * connfig:是一个请求设置对象,包含请求信息
 * 实现功能:客户端向服务端发送请求,通过拦截器请求并检测用户是否已登陆,如果已登陆继续访问该请求
 *          若未登陆,跳转到登陆界面 
 */
Vue.prototype.$axios.interceptors.request.use(function (config) {
    
    
  //检测axios请求路径是否为受限路径
  //在sessionStorage获取当前登陆者信息
  //获得请求访问路径
  let url = config.url;
  //定义匹配放行路径url正则
  let regUrl = /^book\/|^login$|^register$/;
  //处理受限路径
  if (!regUrl.test(url)) {
    
    
    let curUserInfoStr = window.sessionStorage.getItem("curUserInfo");
    if (curUserInfoStr == "" || curUserInfoStr == null) {
    
    //用户未登陆
      let cancel;
      //取消原有请求
      //向config对象中添加一个cancelToken(取消令牌属性)
      config.cancelToken = new axios.CancelToken((c) => {
    
    
        //参数c为一个取消请求的函数
        cancel = c;
      });
      //判断cancel是否为一个函数,若果是,他必定是一个取消请求的函数
      if (typeof cancel == "function") {
    
    
        cancel("请求已取消");
      }

      Swal.fire({
    
    
        icon: 'error',
        title: "请登录后访问",
        showConfirmButton: false,
        timer: 1000,
        didClose: () => {
    
    
          router.push("/login");
        }
      });
      //跳转到登录页
    }
  }
  // 在发送请求之前做些什么
  return config;
}, function (error) {
    
    
  // 对请求错误做些什么
  return Promise.reject(error);
});

4.2 ログに記録されていないアクセスを処理するボタンを無効にする

disabledプロパティを使用して設定する

<el-button type="warning" icon="el-icon-shopping-cart-full" style="margin-left:3px" @click="addCar" :disabled="curUserInfo==null">加入购物车</el-button>

5 ユーザー登録機能の実現

5.1 クライアント

5.1.1 登録ページの UI とルーティング構成

  • 登録ページのUI
<template>
    <div class="win-reg">
        <div class="register-container">
            <h2>用户注册</h2>
            <div class="register-form">
                <el-form ref="form" :model="user" label-width="80px">
                    <el-form-item label="用户名">
                        <el-input v-model="user.user_name" placeholder="请输入用户名"></el-input>
                    </el-form-item>

                    <el-form-item label="密 码">
                        <el-input placeholder="请输入密码" v-model="user.user_password" show-password></el-input>
                    </el-form-item>

                    <el-form-item label="性别">
                        <el-radio-group v-model="user.user_sex" size="medium">
                            <el-radio-button label="1"></el-radio-button>
                            <el-radio-button label="0"></el-radio-button>
                        </el-radio-group>
                    </el-form-item>

                    <el-form-item label="爱好">
                        <el-checkbox-group v-model="user_hobbys_arr" size="medium">
                            <el-checkbox-button v-for="hobby in hobbys" :label="hobby"
                                :key="hobby">{
   
   { hobby }}</el-checkbox-button>
                        </el-checkbox-group>
                    </el-form-item>

                    <el-form-item label="出生日期">
                        <el-date-picker v-model="user.user_birthday" type="date" placeholder="选择日期"
                            value-format="yyyy-MM-dd">
                        </el-date-picker>
                    </el-form-item>


                    <el-form-item label="E-mail">
                        <el-input v-model="user.user_email" placeholder="请输入E-mail"></el-input>
                    </el-form-item>

                    <el-form-item label="地址">
                        <el-input v-model="user.user_address" placeholder="请输入地址"></el-input>
                    </el-form-item>

                </el-form>

            </div>
            <div>
                <el-button type="primary" style="width:100%;margin-bottom:10px;height:50px" @click="register">注册</el-button>
            </div>
        </div>
    </div>
</template>
<script>
export default {
      
      
}
</script>
<style scoped>
.win-reg {
      
      
    position: absolute;
    top: 0px;
    bottom: 0px;
    margin: 0px;
    left: 0px;
    right: 0px;
    padding: 0px;
    display: flex;
    background-color: #dddddd;
    /*设置弹性布局*/
    flex-direction: row;
    /*设置水平方向*/
    justify-content: center;
    /*根据direction的方向设置居中*/
    align-items: center;
    /*根据direction的反方向设置居中*/
}

.register-container {
      
      
    margin: 30px auto;
    width: 500px;
    border: 0px solid red;
    border-radius: 10px;
    background-color: ghostwhite;
    box-shadow: 0px 0px 10px 5px gray;
    padding: 5px;
}

.register-container h2 {
      
      
    text-align: center;
}

.register-form {
      
      
    padding-right: 50px;
}
</style>
  • ルーティング構成
import Register from "../views/Register.vue"
const routes = [
  {
    
    
    path: "/register",
    name: "register",
    component: Register,
  },
];

5.1.2 バックエンドへのデータ転送と対応処理

export default {
    
    
    data() {
    
    
        return {
    
    
            user: {
    
    },
            user_hobbys_arr: [],//绑定复选框的数组
            hobbys: ["篮球", "足球", "听音乐", "网游"]
        }
    },
    methods: {
    
    
        /**
         * 注册函数
         */
        register() {
    
    
            //将ser_hobbys_arr数组中的元素转换为字符串,再将字符串存到user.user_hobbys中
            if (this.user_hobbys_arr.length != 0) {
    
    
                let user_hobbys = "";
                for (let hobby of this.user_hobbys_arr) {
    
    
                    user_hobbys = user_hobbys + "_" + hobby;
                }
                this.user.user_hobbys = user_hobbys.substring(1);
            }
            this.$axios
                .post('register', this.user)
                .then(response => {
    
    
                    let result = response.data;
                    if (result.success) {
    
    
                        this.$swal.fire({
    
    
                            icon: 'success',
                            title: result.message,
                            showConfirmButton: false,
                            timer: 1000,//延迟关闭的时间
                            didClose: () => {
    
    //弹窗关闭后要执行的函数
                                this.$router.push("/");
                            }
                        })
                    } else {
    
    
                        this.$swal.fire({
    
    
                            icon: 'error',
                            title: result.message,
                            showConfirmButton: false,
                            timer: 1000//延迟关闭的时间

                        })
                    }
                })
                .catch(err => {
    
    
                    console.log(err);
                })
        }
    }
}

5.2 サーバー

5.2.1 構成クラスのリリースパス、RegisterController の書き込み

  • 構成クラス
.antMatchers("/book/*","/register")
     .permitAll()//无需认证直接访问
  • RegisterController
@RestController
public class RegisterController {
    
    
    @Resource
    private UserService userService;
    @RequestMapping("/register")
    public Result register(@RequestBody UserInfo userInfo){
    
    
        try {
    
    
            userService.register(userInfo);
            return Result.success("注册成功");
        } catch (Exception e) {
    
    
            e.printStackTrace();
            return Result.fail(500,"注册失败");
        }
    }
}

5.2.2 サービス層の記述

  • UserService インターフェイス
public interface UserService {
    
    
    public void register( UserInfo userInfo) throws Exception;
}
  • UserServiceImpl
@Service
public class UserServiceImp implements UserService {
    
    
    @Resource
    private UserMapper userMapper;
    @Override
    public void register(UserInfo userInfo) throws Exception{
    
    
        //对密码进行加密
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(userInfo.getUser_password());
        userInfo.setUser_password(encode);
        userMapper.register(userInfo);
    }
}

5.2.3 Mapperレイヤーのコンパイル

  • UserMapper
  @Insert("insert into myshopping.tbl_user values (default,#{user_name},#{user_password},#{user_email},#{user_birthday},#{user_hobbys},#{user_sex},#{user_address},0)")
     void register(UserInfo userInfo);

おすすめ

転載: blog.csdn.net/woschengxuyuan/article/details/123830866
おすすめ