【作业题】后台管理系统中的课程管理模块(前端篇)

后端篇:【作业题】后台管理系统中的课程管理模块(后端篇)

项目地址:课程管理模块

功能实现中用到的知识及技巧

1. 项目部署war和war exploded的区别

IDEA中部署项目两种方式

  • war模式:将项目以war包的形式上传到服务器的webapps目录中;

    • 可以称之为发布模式:先打成war包,再发布
  • war exploded模式:将WEB工程以当前文件夹的位置关系上传到服务器,仅仅是目录的映射,就相当于tomcat在项目源文件夹中启动一样;

    • 热部署:一般在开发的时候用这种方式

    在这里插入图片描述

2. 访问图片 upload路径

2.1 在webapps中创建upload目录

upload目录专门用来保存上传过来的图片

2.2 修改代码,将图片上传到服务器

修改图片的输出路径

  1. 获取到项目的运行目录信息

  2. 截取到webapps的 目录路径

  3. 拼接输出路径,将图片保存到upload

    @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            try {
                //1.创建磁盘文件项工厂
                DiskFileItemFactory factory = new DiskFileItemFactory();
    
                //2.创建文件上传核心类
                ServletFileUpload upload = new ServletFileUpload(factory);
                //2.1 设置上传文件名的编码
                upload.setHeaderEncoding("utf-8");
                //2.2 判断表单是否是文件上传表单
                boolean multipartContent = upload.isMultipartContent(req);
                //2.3 是文件上传表单
                if(multipartContent){
    
                    //3. 解析request ,获取文件项集合
                    List<FileItem> list = upload.parseRequest(req);
    
                    if(list != null){
                        //4.遍历获取表单项
                        for (FileItem item : list) {
                            //5. 判断是不是一个普通表单项
                            boolean formField = item.isFormField();
                            if(formField){
                                //普通表单项, 当 enctype="multipart/form-data"时, request的getParameter()方法 无法获取参数
                                String fieldName = item.getFieldName();
                                String value = item.getString("utf-8");//设置编码
                                System.out.println(fieldName + "=" + value);
                            }else{
    
                                //文件上传项
                                //文件名
                                String fileName = item.getName();
                                //避免图片名重复 拼接UUID
                                String newFileName = UUIDUtils.getUUID()+"_"+ fileName;
    
                                //获取上传文件的内容
                                InputStream in = item.getInputStream();
    
                                // 动态获取项目的运行目录
                                String path = this.getServletContext().getRealPath("/");
                                
                                // 截取到 webapps路径
                                String webappsPath = path.substring(0, path.indexOf("lagou_edu_home"));
                                
                                // 拼接输出路径
                                OutputStream out = new FileOutputStream(webappsPath+"/upload/"+newFileName);
                                //拷贝文件到服务器
                                IOUtils.copy(in,out);
    
                                out.close();
                                in.close();
                            }
    
                        }
                    }
                }
            } catch (FileUploadException e) {
                e.printStackTrace();
            }
    
        }
    
2.3 页面加载图片

将tomcat作为图片服务器使用时,存储上传的图片后,如果想要图片可以访问,需要在idea中进行配置:

选择external source —> 找到webapps目录下的的upload文件夹

在这里插入图片描述

在项目内部页面加载图片

<img src="/upload/文件名.jpg">

也可以通过HTTP方式访问

http://localhost:8080/upload/文件名.jpg

3. 跨域问题解决

3.1 出现跨域问题

当我们在前端项目中,向后端发送请求的获取课程数据的时候,出现了跨域问题:

  • 已被CORS策略阻止:请求的资源上没有Access-Control-Allow-Origin标头(跨域请求失败)

    Access to XMLHttpRequest at 'http://localhost:8080/lagou_edu_home/course?
    methodName=findCourseList' from origin 'http://localhost:8088' has been blocked
    by CORS policy: No 'Access-Control-Allow-Origin' header is present on the
    requested resource.
    
3.2 什么是跨域

跨域是指通过JS在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,只要协议、域名、端口有任何一个不同,都被当作是不同的域,浏览器就不允许跨域请求。

  • 跨域常见情况

    在这里插入图片描述

3.3 解决跨域问题

跨域的允许主要由服务器端控制。服务器端通过在响应的 header 中设置 Access-Control-Allow-Origin 及相关一系列参数,提供跨域访问的允许策略。

设置响应头中的参数来允许跨域请求,标识允许跨域的请求有哪些

  • Access-Control-Allow-Credentials
  • Access-Control-Allow-Origin

引入依赖直接解决

  • 在POM文件中引入依赖

    <!-- 解决跨域问题所需依赖 -->
    <dependency>
    <groupId>com.thetransactioncompany</groupId>
    <artifactId>cors-filter</artifactId>
    <version>2.5</version>
    </dependency>
    
  • 在web.xml中 配置跨域 filter

    <!--配置跨域过滤器-->
    <filter>
    <filter-name>corsFilter</filter-name>
    <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>corsFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>
    

4. 路由跳转

4.1 什么是路由?

在Web开发中,路由是指根据URL分配到对应的处理程序。 路由允许我们通过不同的 URL 访问不同的 内容。

通过 Vue.js 可以实现多视图单页面web应用(single page web application,SPA)

  • 单页面Web应用(single page web application,SPA),就是只有一张Web页面的应用, 是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。

官方文档: https://router.vuejs.org/zh-cn/essentials/getting-started.html

观看 Vue School 的关于 Vue Router 的免费视频课程 (英文)

4.2 使用步骤(以login为例)
  1. 定义路由所需的组件
  2. 定义路由
    • path (路径)
    • component (组件)
  3. 创建router路由器实例,管理路由
  4. 创建Vue实例,注入路由对象,使用$mount() 指定挂载点
4.2.1 创建login.vue 组件

创建一个vue项目

在components 下创建login.vue

Dialog对话框组件

根据上述代码自行修改,完整版在下方

4.2.2 配置路由
import Vue from "vue";
import VueRouter from "vue-router";

//导入Login.vue组件
import Login from "@/components/Login";

Vue.use(VueRouter);

const routes = [
  //访问 / .也调转到 login
  {
    path: "/",
    redirect: "login", //重定向到login
  },
  //登录路由
  {
    path: "/login",
    name: "login",
    component: Login,
  },
];

// 解决ElementUI导航栏中的vue-router在3.0版本以上重复点菜单报错问题
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch((err) => err);
};

const router = new VueRouter({
  routes,
});

export default router;
4.2.3 修改App.vue
<template>
  <div id="app">
    <!-- 根据访问路径,渲染路径匹配到的组件 -->
    <router-view></router-view>
  </div>
</template>

<style></style>
4.2.4 编写登录功能
<template>
  <el-dialog
    :show-close="false"
    title="用户登录"
    :visible.sync="dialogFormVisible"
  >
    <el-form>
      <!-- 2.2使用 v-model, 将视图与模型进行绑定 -->
      <el-form-item label="用户名称" :label-width="formLabelWidth">
        <el-input v-model="user.username" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="用户密码" :label-width="formLabelWidth">
        <el-input v-model="user.password" autocomplete="off"></el-input>
      </el-form-item>
    </el-form>

    <div slot="footer" class="dialog-footer">
      <!-- 1.修改登陆触发事件 -->
      <el-button type="primary" @click="login">登 录</el-button>
    </div>
  </el-dialog>
</template>

<script>
export default {
  //2.1 data 中定义数据
  data() {
    return {
      dialogFormVisible: true,
      formLabelWidth: "120px",
      user: { username: "", password: "" },
    };
  },
  methods: {
    //3.编写login方法
    login() {
      //定义常量保存url
      //Postman搭建mock server 模拟一个服务器,模拟后台接口,对请求进行响应
      const url = "https://bdd7f56b-a299-4340-9773-8d3c7c24a6a8.mock.pstmn.io/login";

      //发送请求
      this.axios(url, {
        //携带的参数
        params: {
          username: this.user.username,
          password: this.user.password,
        },
      })
        .then((resp) => {
          console.log(resp);
          alert("登录成功");
          //成功 关闭对话框
          this.dialogFormVisible = false;

          //进行页面跳转,跳转到首页,在前端进行页面跳转 必须使用路由.
          this.$router.push('index'); 
        })
        .catch((error) => {
          //登录失败 提供消息提示
          this.$message.error("对不起!登录失败!");
        });
    },
  },
};
</script>

<style scoped></style>
4.3 路由总结
  1. router是Vue中的路由管理器对象,用来管理路由
  2. route是路由对象,一个路由就对应了一条访问路径,一组路由用routes表示
  3. 每个路由对象都有两部分 path(路径)和component (组件)
  4. router-link 是对a标签的封装,通过to属性指定连接
  5. router-view 路由访问到指定组件后,进行页面展示

5. 前端输入数据保存不成功

5.1 BaseServlet
if("application/json;charset=utf-8".equals(contentType))

修改为:
if ("application/json;charset=utf-8".equalsIgnoreCase(contentType)) // utf-8 || UTF-8(前端传回格式)
5.2 CourseContentServlet

前端发送数据格式

handleAddSection() {
      axios
        .post("/courseContent", {
          methodName: "saveOrUpdateSection",
          section: this.addSectionForm
        })

后端接收格式

// BeanUtils.populate(section, map);
BeanUtils.copyProperties(section, map.get("section"));

6. @click.stop 阻止事件冒泡

6.1 表现形式

点击按钮后,先弹出 button点击事件后弹出 div点击事件,但只需弹出 button点击事件

<body>
    <!-- 事件冒泡: 解决方案 @click.stop -->
    <div id="app" @click="log('div点击事件')">
    	<button @click="log('button点击事件')">事件冒泡</button>
    </div>
    </body>

    <script src="./js/vue.min.js"></script>
    <script>
    var VM = new Vue({
        el: "#app",
        methods: {
        	log(t) {
        		alert(t);
        	},
        },
    });
</script>
6.2 解决方法
<button @click="log('button点击事件')">事件冒泡</button>

修改为:
<button @click.stop="log('button点击事件')">事件冒泡</button>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值