spring boot(学习笔记第二十课) vue + spring boot前后端分离项目练习

news2024/9/22 10:37:53

spring boot(学习笔记第二十课)

  • vue + spring boot前后端分离项目练习

学习内容:

  • 后端程序构建
  • 前端程序构建

1. 后端程序构建

  1. 前后端分离结构
    前后端就是前端程序和后端程序独立搭建,通过Restful API进行交互,进行松耦合的设计。在这里插入图片描述
  2. 后端程序构建
    在网上看到高手构建的示例程序,边学习边在本地构筑。
    光看不练,永远都是停留在表面学习
    • 高手的示例程序。在此感谢高手(江南一点雨)的分享
      示例程序lenve。一个示例的前后端分离示例。
    • copy该工程到本地,之后看到分别的前端构建和后端构建,这里为了使学习过程单纯一点,基本流用后端的构建。前端进行从头的构建练习。 在这里插入图片描述
    • 理解后端构建module结构。
      maven project -> maven module -> maven project。通过maven module的定义,可以
      • 在父maven project里面,定义子的maven module,作为maven sub project
      • 在各个子maven sub project,可以定义dependency关系。
        在这里插入图片描述
    • 本地构建mysql数据库。
      • 本地数据需要建立一系列的表,DDL在DDL定义。注意由于vhr.sql没有考虑表之间的依赖关系,所有不调整顺序的话,在mysql数据库中执行会报错。
      • 调整好的版本调整版,在mysql中执行,创建必要的表。
        在这里插入图片描述
    • 为数据库的连接用户赋予系统表的select权限。
      GRANT SELECT ON performance_schema.user_variables_by_thread TO 'finlay'@'localhost';
      否则,spring boot执行的时候会报错。
    • disable flyway
      设置spring.flyway.enabled=false在文件application.yml中。
      在这里插入图片描述
    • 重新配置vhr-web这个moduleSecurityConfig.java
      在这里插入图片描述
      @Configuration
      @EnableGlobalMethodSecurity(prePostEnabled=true)
      public class SecurityConfig extends WebSecurityConfigurerAdapter {
          @Autowired
          HrService hrService;
          @Autowired
          CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;
          @Autowired
          CustomUrlDecisionManager customUrlDecisionManager;
          @Autowired
          AuthenticationDeniedHandler authenticationDeniedHandler;
      
          @Bean
          PasswordEncoder passwordEncoder() {
              return new BCryptPasswordEncoder();
          }
      
          @Override
          protected void configure(AuthenticationManagerBuilder auth) throws Exception {
              auth.userDetailsService(hrService);
          }
      
          @Override
          public void configure(WebSecurity web) throws Exception {
              web.ignoring().antMatchers(
                      "/css/**", "/js/**", "/index.html",
                      "/img/**", "/fonts/**", "/favicon.ico", "/verifyCode");
          }
      
          @Bean
          SessionRegistryImpl sessionRegistry() {
              return new SessionRegistryImpl();
          }
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http.authorizeRequests()
                      .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                          @Override
                          public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                              object.setAccessDecisionManager(customUrlDecisionManager);
                              object.setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource);
                              return object;
                          }
                      })
                      .and()
                      .formLogin().loginPage("/login_p").loginProcessingUrl("/login")
                      .usernameParameter("username").passwordParameter("password")
                      .failureHandler(new AuthenticationFailureHandler() {
                          @Override
                          public void onAuthenticationFailure(HttpServletRequest request,
                                                              HttpServletResponse response,
                                                              AuthenticationException exception) throws IOException, ServletException {
                              response.setContentType("application/json;charset=utf-8");
                              RespBean respBean = null;
                              if(exception instanceof BadCredentialsException
                                  || exception instanceof UsernameNotFoundException){
                                  respBean = RespBean.error("用户名或者密码输入错误");
                              }else if(exception instanceof LockedException) {
                                  respBean = RespBean.error("用户名被锁定,请联系管理员");
                              }else {
                                  respBean = RespBean.error("登陆失败");
                              }
                              respBean.setStatus(401);
                              ObjectMapper om = new ObjectMapper();
                              PrintWriter printWriter = response.getWriter();
                              printWriter.write(om.writeValueAsString(respBean));
                              printWriter.flush();
                              printWriter.close();
                          }
                      })
                      .successHandler(new AuthenticationSuccessHandler() {
                          @Override
                          public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                             response.setContentType("application/json;charset=utf-8");
                             RespBean respBean = RespBean.ok("登陆成功", HrUtils.getCurrentHr());
                             ObjectMapper om = new ObjectMapper();
                             PrintWriter printWriter = response.getWriter();
                             printWriter.write(om.writeValueAsString(respBean));
                             printWriter.flush();
                             printWriter.close();
                          }
                      })
                      .permitAll()
                      .and()
                      .csrf().disable().exceptionHandling()
                      //没有认证时,在这里处理结果,不要重定向
                      .accessDeniedHandler(authenticationDeniedHandler);
          }
      }
      
    • 认证处理如下所示。在这里插入图片描述
    • mailserver中加入必要的依赖。
       <dependency>
                  <groupId>junit</groupId>
                  <artifactId>junit</artifactId>
                  <version>4.13.2</version>
                  <scope>test</scope>
      </dependency>
      
    • 启动后端程序需要的redis
      sudo -i
      systemctl restart redis
      
    • 配置redis
      application.yml(spring.redis)
        redis:
          host: 192.168.12.135
          database: 0
          port: 6379
          password: 123456
      
      在这里插入图片描述
    • 启动后端程序vhr
      注意端口使用8081,之后的前端端口默认8080避免冲突 在这里插入图片描述 * 首先启动postman进行测试,使用admin这个user
      在这里插入图片描述

2. 前端程序构建

  1. 构建前端工程
    前端采用Vue进行构建。
    • 执行npm进行搭建
      执行以下命令,建立vue工程
      npm install -g vue-cli
      vue init webpack vuehr
      cd vuehr
      npm run dev
      
      默认是8080端口 注意,后端工程的端口必须和前端工程的端口分开,这里后端采用的是8081
  2. 构建前端的认证画面和路由
    • 前端使用Element(画面表示)和AxiosAjax后端交互)
      npm i element-ui -S
      npm i axios -S
      
    • 修改axios的默认版数
      默认的axios版数,在之后的练习中会编译错误,所以改修成"axios": "^0.19.0"
      修改
      "dependencies": {
          "axios": "^0.19.0",
        },
      ```![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c95f0d23e2714fad9d588a14b85e5b24.png)
      
    • 导入必要的代码
      • 在main.js中加入Element
        import ElementUI from 'element-ui'
        import 'element-ui/lib/theme-chalk/index.css'
        Vue.use(ElementUI)
        
      • 在项目中加入/utils/api
        从前面clone下来的代码中,将utils/api这个代码,都copy到新的代码段中。在这里插入图片描述
        • 在main.js中加入/utils/api
        import { getRequest, postRequest, deleteRequest, putRequest } from './utils/api'
        
        Vue.prototype.getRequest = getRequest
        Vue.prototype.postRequest = postRequest
        Vue.prototype.deleteRequest = deleteRequest
        Vue.prototype.putRequest = putRequest
        
        • 开发login页面
        <template>
          <el-form :rules="rules" class="login-container" label-position="left"
          label-width="0px" v-loading="loading">
          <h3 class="login_title">系统登陆</h3>
          <el-form-item prop="account">
           <el-input type="text" v-model="loginForm.username"
           auto-complete="off" placeholder="账号"></el-input>
          </el-form-item>
          <el-form-item prop="checkPass">
           <el-input type="password" v-model="loginForm.password"
           auto-complete="off" placeholder="密码">
           </el-input>
          </el-form-item>
          <el-checkbox class="login_remember" v-model="checked"
          label-position="left">记住密码</el-checkbox>
          <el-form-item style="width: 100%">
           <el-button type="primary" style="width: 100%"
           @click="submitClick">登录</el-button>
          </el-form-item>
          </el-form>
        </template>
        <script>
        export default{
          data () {
            return {
              rules: {
                account: [{required: true, message: '请输入用户名', trigger: 'blur'}],
                checkPass: [{required: true, message: '请输入密码', trigger: 'blur'}]
              },
              checked: true,
              loginForm: {
                username: 'admin',
                password: '123'
              },
              loading: false
            }
          },
          methods: {
            submitClick: function () {
              var _this = this
              this.loading = true
              this.postRequest("/login?username=" + this.loginForm.username +
              "&password=" + this.loginForm.password
              ).then((resp) => {
                _this.loading = false
                if (resp && resp.status === 200) {
                  var data = resp.data
                  //_this.$store.commit('login', data.obj)
                  var path = _this.$route.query.redirect
                  _this.$router.replace({
                    path: path === '/' || path === undefined ? '/home' : path
                  })
                }
              })
            }
          }
        }
        </script>
        <style>
          .login-container {
            border-radius: 15px;
            background-clip: padding-box;
            margin: 150px auto;
            width: 350px;
            padding: 35px 35px 15px 35px;
            background: #fff;
            border: 1px solid #cac6c6;
            box-shadow: 0 0 25px #cac6c6;
          }
          .login_title {
            margin: 0px auto 40px auto;
            text-align: center;
            color: #505458;
          }
          .login_remember {
            margin: 0px 0px 35px 0px;
            text-align: left;
          }
        </style>
        
        • 修改路由表route/index.js
        import Vue from 'vue'
        import Router from 'vue-router'
        import HelloWorld from '@/components/HelloWorld'
        import Login from '@/components/Login'
        
        Vue.use(Router)
        
        export default new Router({
          routes: [
            {
              path: '/',
              name: 'Login',
              component: Login,
              hidden: true
            }, {
              path: '/home',
              name: '主页',
              component: HelloWorld
            }
          ]
        })
        
        • 修改主程序入口src/App.vue
        <template>
          <div id="app">
            <router-view/>
          </div>
        </template>
        
        <script>
        export default {
          name: 'App'
        }
        </script>
        
        <style>
        #app {
          font-family: 'Avenir', Helvetica, Arial, sans-serif;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
          text-align: center;
          color: #2c3e50;
          margin-top: 60px;
        }
        </style>
        
        • 配置前端转发config/index.js
          前端8080和后端8081在不同的端口,这里必须要在前端设置后端的端口。
        proxyTable: {
              '/': {
                target: 'http://localhost:8081',
                changeOrigin: true,
                pathRewrite: {
                  '^/': ''
                }
              },
              '/ws/*': {
                target: 'ws://127.0.0.1:8081',
                ws: true
              }
            },
        
    • 启动前端程序
      shell npm run dev
      在这里插入图片描述
      • 输入和数据库hr表里面的用户名和密码
        登录成功,进入到home画面。在这里插入图片描述hr表的用户名和密码,登录系统。
    • 前端Vue工程的结构

      接下来对系统管理的菜单页面进行练习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2154870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【吊打面试官系列-MySQL面试题】MySQL_fetch_array 和 MySQL_fetch_object 的区别是什么?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL_fetch_array 和 MySQL_fetch_object 的区别是什么&#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; MySQL_fetch_array 和 MySQL_fetch_object 的区别是什么&#xff1f; 以下是 MySQL_fetch_array 和 MySQL_fe…

VisionPro - 基础 - 模板匹配技术和在VP中的使用 - PMAlign - PatMax (5)- 非线性模板变形匹配

前言&#xff1a; 本机继续对VP的PatMax 算子进行说明&#xff1a;本节讲非线性变形的模板匹配。 Non-Linear Pattern Deformation By default, PatMax requires that each boundary point in the instance of a pattern found in a run-time image closely correspond to a b…

低空经济火爆,稀缺无人机教员培训详解

随着科技的飞速发展和低空经济的日益火爆&#xff0c;无人机技术已广泛应用于航拍、农业、物流、救援、环境监测等多个领域&#xff0c;成为推动社会经济发展的新引擎。然而&#xff0c;无人机行业的快速发展也催生了对专业无人机教员的迫切需求。本文将从基础理论学习、实操技…

[Redis][List]详细讲解

目录 0.前言1.常用命令1.LPUSH / RPUSH2.LPUSHX / RPUSHX3.LRANGE4.LPOP / RPOP5.LINDEX6.LINSERT7.LLEN8.LREM9.LTRIM10.LSET 2.阻塞版本命令0.是什么&#xff1f;1.BLPOP / BRPOP 3.内部编码(旧版本&#xff0c;仅供参考)1.ziplist(压缩链表)2.linkedlist(链表)3.quicklist(快…

yolov8旋转目标检测之绝缘子检测-从数据加载到模型训练、部署

YOLOv8 是 YOLO (You Only Look Once) 系列目标检测算法的最新版本&#xff0c;以其高速度和高精度而著称。在电力行业中&#xff0c;绝缘子是电力传输线路上的重要组件之一&#xff0c;它们用于支撑导线并保持电气绝缘。由于长期暴露在户外环境中&#xff0c;绝缘子容易出现损…

详细分析Spring的动态代理机制

文章目录 1. JDK动态代理和CGLIB动态代理的区别1.1 适用范围1.2 生成的代理类1.3 调用方式 2. 问题引入3. 创建工程验证 Spring 默认采用的动态代理机制3.1 引入 Maven 依赖3.2 UserController.java3.3 UserService.java3.4 UserServiceImpl.java&#xff08;save方法添加了Tra…

【Python】探索 TensorFlow:构建强大的机器学习模型

TensorFlow 是一个开源的深度学习框架&#xff0c;由 Google 开发&#xff0c;广泛应用于机器学习和人工智能领域。自从 2015 年推出以来&#xff0c;它已成为研究人员、开发者和数据科学家们不可或缺的工具。TensorFlow 提供了灵活、高效的工具集&#xff0c;可以帮助我们构建…

API接口在金融科技领域的创新应用

导语&#xff1a; 随着互联网的发展和技术的进步&#xff0c;API接口在金融科技领域的创新应用越来越受到关注。本文将介绍API接口的基本概念&#xff0c;以及它在金融科技领域的应用案例。 第一部分&#xff1a;API接口简介及原理 API是Application Programming Interface&…

2021-03-03人工智能应用的就业效应

【摘要】文章从人工智能的概念出发&#xff0c;在总结已有研究方法的基础上&#xff0c;回顾了人工智能对就业的产业分布、岗位、工资等方面影响的理论与实证研究。文章发现&#xff0c;人工智能技术在替代部分岗位、促使劳动力在不同产业间流动的同时&#xff0c;还会加快劳动…

java 获取集合a比集合b多出来的对象元素

public class OrderListEntity {/*** deprecated 对象集合的处理* param aData 集合a* param bData 集合b* return 返回集合a比集合b多出来的部分, 通过id判断*/public static List<OrderListEntity> AHasMoreThanBData(List<OrderListEntity> aData, List<Ord…

LEAN 赋型唯一性(Unique Typing)之 Church-Rosser 定理 (Church-Rosser Theorem)及 赋型唯一性的证明

有了并行K简化的概念及其属性&#xff0c;以及其在LEAN类型理论中的相关证明&#xff0c;就可以证明&#xff0c;在K简化下的Church-Rosser 定理。即&#xff1a; 其过程如下&#xff1a; 证明如下&#xff1a; 其中的 lemma 4.9 和 4.10 &#xff0c;及 4.8 是 这整个证明过程…

华为云centos7.9按装ambari 2.7.5 hostname 踩坑记录

华为云centos7.9按装ambari 2.7.5踩坑记录 前言升华总结 前言 一般都是废话&#xff0c;本人专业写bug业余运维。起初找了三台不废弃的台式机&#xff0c;开始重装centos系统&#xff0c;开始了HDP3.1.5Ambari2.7.5安装。 推荐一波好文&#xff0c;一路长绿。跑了一段时间没啥…

2024年最新版TypeScript学习笔记——泛型、接口、枚举、自定义类型等知识点

今天带来的是来自尚硅谷禹神2024年8月最新的TS课程的学习笔记&#xff0c;不得不说禹神讲的是真的超级棒&#xff01; 文章目录 TS入门JS中的困扰静态类型检查编译TS命令行编译自动化编译 类型检查变量和函数类型检查字面量类型检查 类型推断类型声明声明对象类型声明函数类型…

深度学习02-pytorch-08-自动微分模块

​​​​​​​ 其实自动微分模块&#xff0c;就是求相当于机器学习中的线性回归损失函数的导数。就是求梯度。 反向传播的目的&#xff1a; 更新参数&#xff0c; 所以会使用到自动微分模块。 神经网络传输的数据都是 float32 类型。 案例1: 代码功能概述&#xff1a; 该…

【Python篇】深入机器学习核心:XGBoost 从入门到实战

文章目录 XGBoost 完整学习指南&#xff1a;从零开始掌握梯度提升1. 前言2. 什么是XGBoost&#xff1f;2.1 梯度提升简介 3. 安装 XGBoost4. 数据准备4.1 加载数据4.2 数据集划分 5. XGBoost 基础操作5.1 转换为 DMatrix 格式5.2 设置参数5.3 模型训练5.4 预测 6. 模型评估7. 超…

重生之我们在ES顶端相遇第14 章 - ES 节点类型

文章目录 前言Coordinating nodeMaster-eligible nodeData nodeCoordinating only nodeRemote-eligible nodeMachine learning node 前言 通过前面的学习&#xff0c;我们已经初步的掌握了 ES 的大部分用法。 后面的篇章会介绍 ES 集群相关的内容。 本文着重介绍 ES 节点类型&…

华为HarmonyOS地图服务 3 - 如何开启和展示“我的位置”?

一. 场景介绍 本章节将向您介绍如何开启和展示“我的位置”功能&#xff0c;“我的位置”指的是进入地图后点击“我的位置”显示当前位置点的功能。效果如下&#xff1a; 二. 接口说明 “我的位置”功能主要由MapComponentController的方法实现&#xff0c;更多接口及使用方法…

软考高级:逻辑地址和物理地址转换 AI解读

一、题目 设某进程的段表如下所示&#xff0c;逻辑地址&#xff08; &#xff09;可以转换为对应的物理地址。 A. &#xff08;0&#xff0c;1597&#xff09;、&#xff08;1&#xff0c;30&#xff09;和&#xff08;3&#xff0c;1390&#xff09; B. &#xff08;0&…

Vue3 中组件传递 + css 变量的组合

文章目录 需求效果如下图所示代码逻辑代码参考 需求 开发一个箭头组件&#xff0c;根据父组件传递的 props 来修改 css 的颜色 效果如下图所示 代码逻辑 代码 父组件&#xff1a; <Arrow color"red" />子组件&#xff1a; <template><div class&…

3DMAX乐高积木插件LegoBlocks使用方法

3DMAX乐高积木插件LegoBlocks&#xff0c;用户可以通过控件调整和自定义每个乐高积木的外观和大小。 【适用版本】 3dMax2009或更高版本&#xff08;不仅限于此范围&#xff09; 【安装方法】 3DMAX乐高积木插件无需安装&#xff0c;使用时直接拖动插件脚本文件到3dMax视口中…