瑞吉外卖笔记(分析瑞吉外卖)
1.数据库环境搭建
创建数据库
create database reggie character set utf8mb4;
执行sql命令,注意该脚本不要放在中文目录中。
mysql > source D:/db_reggie.sql
2.maven项目创建
注意检查项目编码,jdk配置,maven配置。
3.定义pom.xml文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.5</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.itheima</groupId> <artifactId>reggie_take_out</artifactId> <version>1.0-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!--阿里云短信服务--> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-core</artifactId> <version>4.5.16</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>aliyun-java-sdk-dysmsapi</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <scope>compile</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--MyBatis的分页插件--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.10</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.23</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.4.5</version> </plugin> </plugins> <!-- 打包时拷贝MyBatis的映射文件 --> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.yml</include> <include>**/sqlmap/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> <filtering>true</filtering> </resource> </resources> </build> </project>4.定义springboot配置文件application.yml
server: port: 8080 spring: application: #应用的名称,可选 name: reggie_take_out datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/xuetoucloud?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true username: root password: caicai123 max-active: 100 initial-size: 1 max-wait: 60000 min-idle: 1 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 validation-query: select 'x' test-while-idle: true test-on-borrow: false test-on-return: false pool-prepared-statements: true max-open-prepared-statements: 50 max-pool-prepared-statement-per-connection-size: 20 mybatis-plus: mapper-locations: classpath:/mapper/**.xml configuration: #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射 map-underscore-to-camel-case: true log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: id-type: ASSIGN_ID reggie: path: D:\img\5.启动类
package com.itheima.reggie; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.transaction.annotation.EnableTransactionManagement; @Slf4j //@SpringBootApplication(scanBasePackages={"com.itheima.reggie"}) @SpringBootApplication @ServletComponentScan @EnableTransactionManagement public class ReggieApplication { public static void main(String[] args) { SpringApplication.run(ReggieApplication.class,args); log.info("项目启动成功..."); } } 6.配置静态资源映射,访问html、js、css等静态文件。
在config包添加配置
package com.itheima.reggie.config; import com.itheima.reggie.common.JacksonObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import java.util.List; @Slf4j @Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { /** * 设置静态资源映射 * @param registry */ @Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { log.info("开始进行静态资源映射..."); registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/"); registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/"); } /** * 扩展mvc框架的消息转换器 * @param converters */ @Override protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { log.info("扩展消息转换器..."); //创建消息转换器对象 MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter(); //设置对象转换器,底层使用Jackson将Java对象转为json messageConverter.setObjectMapper(new JacksonObjectMapper()); //将上面的消息转换器对象追加到mvc框架的转换器集合中 converters.add(0,messageConverter); } } 7.开发登陆功能
package com.itheima.reggie.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.itheima.reggie.common.R; import com.itheima.reggie.entity.Employee; import com.itheima.reggie.service.EmployeeService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.DigestUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.time.LocalDateTime; @Slf4j @RestController @RequestMapping("/employee") public class EmployeeController { @Autowired private EmployeeService employeeService; /** * 员工登录 * @param request * @param employee * @return */ @PostMapping("/login") public R<Employee> login(HttpServletRequest request,@RequestBody Employee employee){ //1、将页面提交的密码password进行md5加密处理 String password = employee.getPassword(); password = DigestUtils.md5DigestAsHex(password.getBytes()); //2、根据页面提交的用户名username查询数据库 LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Employee::getUsername,employee.getUsername()); Employee emp = employeeService.getOne(queryWrapper); //3、如果没有查询到则返回登录失败结果 if(emp == null){ return R.error("登录失败"); } //4、密码比对,如果不一致则返回登录失败结果 if(!emp.getPassword().equals(password)){ return R.error("登录失败"); } //5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果 if(emp.getStatus() == 0){ return R.error("账号已禁用"); } //6、登录成功,将员工id存入Session并返回登录成功结果 request.getSession().setAttribute("employee",emp.getId()); return R.success(emp); } /** * 员工退出 * @param request * @return */ @PostMapping("/logout") public R<String> logout(HttpServletRequest request){ //清理Session中保存的当前登录员工的id request.getSession().removeAttribute("employee"); return R.success("退出成功"); } } <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>瑞吉外卖管理端</title> <link rel="shortcut icon" href="../../favicon.ico"> <!-- 引入样式 --> <link rel="stylesheet" href="../../plugins/element-ui/index.css" /> <link rel="stylesheet" href="../../styles/common.css"> <link rel="stylesheet" href="../../styles/login.css"> <link rel="stylesheet" href="../../styles/icon/iconfont.css" /> <style> .body{ min-width: 1366px; } </style> </head> <body> <div class="login" id="login-app"> <div class="login-box"> <img src="../../images/login/login-l.png" alt=""> <div class="login-form"> <el-form ref="loginForm" :model="loginForm" :rules="loginRules" > <div class="login-form-title"> <img src="../../images/login/logo.png" style="width:139px;height:42px;" alt="" /> </div> <el-form-item prop="username"> <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="账号" maxlength="20" prefix-icon="iconfont icon-user" /> </el-form-item> <el-form-item prop="password"> <el-input v-model="loginForm.password" type="password" placeholder="密码" prefix-icon="iconfont icon-lock" maxlength="20" @keyup.enter.native="handleLogin" /> </el-form-item> <el-form-item style="width:100%;"> <el-button :loading="loading" class="login-btn" size="medium" type="primary" style="width:100%;" @click.native.prevent="handleLogin"> <span v-if="!loading">登录</span> <span v-else>登录中...</span> </el-button> </el-form-item> </el-form> </div> </div> </div> <!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="../../plugins/vue/vue.js"></script> <!-- 引入组件库 --> <script src="../../plugins/element-ui/index.js"></script> <!-- 引入axios --> <script src="../../plugins/axios/axios.min.js"></script> <script src="../../js/request.js"></script> <script src="../../js/validate.js"></script> <script src="../../api/login.js"></script> <script> new Vue({ el: '#login-app', data() { return { loginForm:{ username: 'admin', password: '123456' }, loading: false } }, computed: { loginRules() { const validateUsername = (rule, value, callback) => { if (value.length < 1 ) { callback(new Error('请输入用户名')) } else { callback() } } const validatePassword = (rule, value, callback) => { if (value.length < 6) { callback(new Error('密码必须在6位以上')) } else { callback() } } return { 'username': [{ 'validator': validateUsername, 'trigger': 'blur' }], 'password': [{ 'validator': validatePassword, 'trigger': 'blur' }] } } }, created() { }, methods: { async handleLogin() { this.$refs.loginForm.validate(async (valid) => { if (valid) { this.loading = true let res = await loginApi(this.loginForm) if (String(res.code) === '1') {//1表示登录成功 localStorage.setItem('userInfo',JSON.stringify(res.data)) window.location.href= '/backend/index.html' } else { this.$message.error(res.msg) this.loading = false } } }) } } }) </script> </body> </html> function loginApi(data) { return $axios({ 'url': '/employee/login', 'method': 'post', data }) } function logoutApi(){ return $axios({ 'url': '/employee/logout', 'method': 'post', }) } 注意:localStorage在浏览器保存为json数据,表示用户已登录
localStorage.setItem('userInfo',JSON.stringify(res.data))登陆成功之后做页面跳转
window.location.href= '/backend/index.html'8.定义员工表实体类,用来和数据库映射
package com.itheima.reggie.entity; import com.baomidou.mybatisplus.annotation.FieldFill; import com.baomidou.mybatisplus.annotation.TableField; import lombok.Data; import java.io.Serializable; import java.time.LocalDateTime; /** * 员工实体 */ @Data public class Employee implements Serializable { private static final long serialVersionUID = 1L; private Long id; private String username; private String name; private String password; private String phone; private String sex; private String idNumber;//身份证号码 private Integer status; @TableField(fill = FieldFill.INSERT) //插入时填充字段 private LocalDateTime createTime; @TableField(fill = FieldFill.INSERT_UPDATE) //插入和更新时填充字段 private LocalDateTime updateTime; @TableField(fill = FieldFill.INSERT) //插入时填充字段 private Long createUser; @TableField(fill = FieldFill.INSERT_UPDATE) //插入和更新时填充字段 private Long updateUser; } 9.登陆代码开发,Controller,Service,Mapper
Controller
package com.itheima.reggie.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.itheima.reggie.common.R; import com.itheima.reggie.entity.Employee; import com.itheima.reggie.service.EmployeeService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.DigestUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.time.LocalDateTime; @Slf4j @RestController @RequestMapping("/employee") public class EmployeeController { @Autowired private EmployeeService employeeService; /** * 员工登录 * @param request * @param employee * @return */ @PostMapping("/login") public R<Employee> login(HttpServletRequest request,@RequestBody Employee employee){ //1、将页面提交的密码password进行md5加密处理 String password = employee.getPassword(); password = DigestUtils.md5DigestAsHex(password.getBytes()); //2、根据页面提交的用户名username查询数据库 LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Employee::getUsername,employee.getUsername()); Employee emp = employeeService.getOne(queryWrapper); //3、如果没有查询到则返回登录失败结果 if(emp == null){ return R.error("登录失败"); } //4、密码比对,如果不一致则返回登录失败结果 if(!emp.getPassword().equals(password)){ return R.error("登录失败"); } //5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果 if(emp.getStatus() == 0){ return R.error("账号已禁用"); } //6、登录成功,将员工id存入Session并返回登录成功结果 request.getSession().setAttribute("employee",emp.getId()); return R.success(emp); } /** * 员工退出 * @param request * @return */ @PostMapping("/logout") public R<String> logout(HttpServletRequest request){ //清理Session中保存的当前登录员工的id request.getSession().removeAttribute("employee"); return R.success("退出成功"); } /** * 新增员工 * @param employee * @return */ @PostMapping public R<String> save(HttpServletRequest request,@RequestBody Employee employee){ log.info("新增员工,员工信息:{}",employee.toString()); //设置初始密码123456,需要进行md5加密处理 employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes())); // employee.setCreateTime(LocalDateTime.now()); // employee.setUpdateTime(LocalDateTime.now()); // // //获得当前登录用户的id // Long empId = (Long) request.getSession().getAttribute("employee"); // employee.setCreateUser(empId); // employee.setUpdateUser(empId); employeeService.save(employee); return R.success("新增员工成功"); } /** * 员工信息分页查询 * @param page * @param pageSize * @param name * @return */ @GetMapping("/page") public R<Page> page(int page, int pageSize, String name){ log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name); Long id = Thread.currentThread().getId(); log.info("线程ID{}",id); //构造分页构造器 Page pageInfo = new Page(page,pageSize); //构造条件构造器 LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper(); //添加过滤条件 queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name); //添加排序条件 queryWrapper.orderByDesc(Employee::getUpdateTime); //执行查询 employeeService.page(pageInfo,queryWrapper); return R.success(pageInfo); } /** * 根据id修改员工信息 * @param employee * @return */ @PutMapping public R<String> update(HttpServletRequest request,@RequestBody Employee employee){ log.info(employee.toString()); Long id = Thread.currentThread().getId(); log.info("线程ID{}",id); Long empId = (Long)request.getSession().getAttribute("employee"); //employee.setUpdateTime(LocalDateTime.now()); //employee.setUpdateUser(empId); employeeService.updateById(employee); return R.success("员工信息修改成功"); } /** * 根据id查询员工信息 * @param id * @return */ @GetMapping("/{id}") public R<Employee> getById(@PathVariable Long id){ log.info("根据id查询员工信息..."); Employee employee = employeeService.getById(id); if(employee != null){ return R.success(employee); } return R.error("没有查询到对应员工信息"); } } Service
package com.itheima.reggie.service; import com.baomidou.mybatisplus.extension.service.IService; import com.itheima.reggie.entity.Employee; public interface EmployeeService extends IService<Employee> { } EmployeeServiceImpl
package com.itheima.reggie.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.itheima.reggie.entity.Employee; import com.itheima.reggie.mapper.EmployeeMapper; import com.itheima.reggie.service.EmployeeService; import org.springframework.stereotype.Service; @Service public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper,Employee> implements EmployeeService{ } 10.通用返回结果类
使用方式举例,
返回成功结果,return R.success(employee);
返回失败信息,return R.error("没有查询到对应员工信息");
定义编码code,1表示成功,0和其它数字为失败
package com.itheima.reggie.common; import lombok.Data; import java.util.HashMap; import java.util.Map; /** * 通用返回结果,服务端响应的数据最终都会封装成此对象 * @param <T> */ @Data public class R<T> { private Integer code; //编码:1成功,0和其它数字为失败 private String msg; //错误信息 private T data; //数据 private Map map = new HashMap(); //动态数据 public static <T> R<T> success(T object) { R<T> r = new R<T>(); r.data = object; r.code = 1; return r; } public static <T> R<T> error(String msg) { R r = new R(); r.msg = msg; r.code = 0; return r; } public R<T> add(String key, Object value) { this.map.put(key, value); return this; } } @PostMapping("/login") public R<Employee> login(HttpServletRequest request,@RequestBody Employee employee){ post请求传递json数据,请加注解@RequestBody
//6、登录成功,将员工id存入Session并返回登录成功结果 request.getSession().setAttribute("employee",emp.getId()); return R.success(emp);11.员工退出
/** * 员工退出 * @param request * @return */ @PostMapping("/logout") public R<String> logout(HttpServletRequest request){ //清理Session中保存的当前登录员工的id request.getSession().removeAttribute("employee"); return R.success("退出成功"); }12.首页
使用vue中的data的menuList生成左侧导航
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>瑞吉外卖管理端</title> <link rel="shortcut icon" href="favicon.ico"> <!-- 引入样式 --> <link rel="stylesheet" href="plugins/element-ui/index.css" /> <link rel="stylesheet" href="styles/common.css" /> <link rel="stylesheet" href="styles/index.css" /> <link rel="stylesheet" href="styles/icon/iconfont.css" /> <style> .body{ min-width: 1366px; } .app-main{ height: calc(100% - 64px); } .app-main .divTmp{ width: 100%; height: 100%; } </style> </head> <body> <div class="app" id="app"> <div class="app-wrapper openSidebar clearfix"> <!-- sidebar --> <div class="sidebar-container"> <div class="logo"> <!-- <img src="images/logo.png" width="122.5" alt="" /> --> <img src="images/login/login-logo.png" alt="" style="width: 117px; height: 32px" /> </div> <el-scrollbar wrap-class="scrollbar-wrapper"> <el-menu :default-active="defAct" :unique-opened="false" :collapse-transition="false" background-color="#343744" text-color="#bfcbd9" active-text-color="#f4f4f5" > <div v-for="item in menuList" :key="item.id"> <el-submenu :index="item.id" v-if="item.children && item.children.length>0"> <template slot="title"> <i class="iconfont" :class="item.icon"></i> <span>{{item.name}}</span> </template> <el-menu-item v-for="sub in item.children" :index="sub.id" :key="sub.id" @click="menuHandle(sub,false)" > <i :class="iconfont" :class="sub.icon"></i> <span slot="title">{{sub.name}}</span> </el-menu-item > </el-submenu> <el-menu-item v-else :index="item.id" @click="menuHandle(item,false)"> <i class="iconfont" :class="item.icon"></i> <span slot="title">{{item.name}}</span> </el-menu-item> </div> </el-menu> </el-scrollbar> </div> <div class="main-container"> <!-- <navbar /> --> <div class="navbar"> <div class="head-lable"> <span v-if="goBackFlag" class="goBack" @click="goBack()" ><img src="images/icons/[email protected]" alt="" /> 返回</span > <span>{{headTitle}}</span> </div> <div class="right-menu"> <div class="avatar-wrapper">{{ userInfo.name }}</div> <!-- <div class="logout" @click="logout">退出</div> --> <img src="images/icons/[email protected]" class="outLogin" alt="退出" @click="logout" /> </div> </div> <div class="app-main" v-loading="loading"> <div class="divTmp" v-show="loading"></div> <iframe id="cIframe" class="c_iframe" name="cIframe" :src="iframeUrl" width="100%" height="auto" frameborder="0" v-show="!loading" ></iframe> </div> </div> </div> </div> <!-- 开发环境版本,包含了有帮助的命令行警告 --> <script src="plugins/vue/vue.js"></script> <!-- 引入组件库 --> <script src="plugins/element-ui/index.js"></script> <!-- 引入axios --> <script src="plugins/axios/axios.min.js"></script> <script src="js/request.js"></script> <script src="./api/login.js"></script> <script> new Vue({ el: '#app', data() { return { defAct: '2', menuActived: '2', userInfo: {}, menuList: [ // { // id: '1', // name: '门店管理', // children: [ { id: '2', name: '员工管理', url: 'page/member/list.html', icon: 'icon-member' }, { id: '3', name: '分类管理', url: 'page/category/list.html', icon: 'icon-category' }, { id: '4', name: '菜品管理', url: 'page/food/list.html', icon: 'icon-food' }, { id: '5', name: '套餐管理', url: 'page/combo/list.html', icon: 'icon-combo' }, { id: '6', name: '订单列表', url: 'page/order/list.html', icon: 'icon-order' }, { id: '7', name: '订单明细', url: 'page/order/list2.html', icon: 'icon-order' } // ], // }, ], iframeUrl: 'page/member/list.html', headTitle: '员工管理', goBackFlag: false, loading: true, timer: null } }, computed: {}, created() { const userInfo = window.localStorage.getItem('userInfo') if (userInfo) { this.userInfo = JSON.parse(userInfo) } this.closeLoading() }, beforeDestroy() { this.timer = null clearTimeout(this.timer) }, mounted() { window.menuHandle = this.menuHandle }, methods: { logout() { logoutApi().then((res)=>{ if(res.code === 1){ localStorage.removeItem('userInfo') window.location.href = '/backend/page/login/login.html' } }) }, goBack() { // window.location.href = 'javascript:history.go(-1)' const menu = this.menuList.find(item=>item.id===this.menuActived) // this.goBackFlag = false // this.headTitle = menu.name this.menuHandle(menu,false) }, menuHandle(item, goBackFlag) { this.loading = true this.menuActived = item.id this.iframeUrl = item.url this.headTitle = item.name this.goBackFlag = goBackFlag this.closeLoading() }, closeLoading(){ this.timer = null this.timer = setTimeout(()=>{ this.loading = false },1000) } } }) </script> </body> </html> 使用v-for遍历菜单列表生成菜单
<div v-for="item in menuList" :key="item.id"> <el-submenu :index="item.id" v-if="item.children && item.children.length>0"> <template slot="title"> <i class="iconfont" :class="item.icon"></i> <span>{{item.name}}</span> </template> <el-menu-item v-for="sub in item.children" :index="sub.id" :key="sub.id" @click="menuHandle(sub,false)" > <i :class="iconfont" :class="sub.icon"></i> <span slot="title">{{sub.name}}</span> </el-menu-item > </el-submenu> <el-menu-item v-else :index="item.id" @click="menuHandle(item,false)"> <i class="iconfont" :class="item.icon"></i> <span slot="title">{{item.name}}</span> </el-menu-item> </div>菜单单击事件
menuHandle(item, goBackFlag) { this.loading = true this.menuActived = item.id this.iframeUrl = item.url this.headTitle = item.name this.goBackFlag = goBackFlag this.closeLoading() }iframe显示网页
<div class="app-main" v-loading="loading"> <div class="divTmp" v-show="loading"></div> <iframe id="cIframe" class="c_iframe" name="cIframe" :src="iframeUrl" width="100%" height="auto" frameborder="0" v-show="!loading" ></iframe> </div>13.禁止未登录进行访问
创建过滤器LoginCheckFilter
package com.itheima.reggie.filter; import com.alibaba.fastjson.JSON; import com.itheima.reggie.common.BaseContext; import com.itheima.reggie.common.R; import lombok.extern.slf4j.Slf4j; import org.springframework.util.AntPathMatcher; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * 检查用户是否已经完成登录 */ @WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*") @Slf4j public class LoginCheckFilter implements Filter{ //路径匹配器,支持通配符 public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher(); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; //1、获取本次请求的URI String requestURI = request.getRequestURI();// /backend/index.html log.info("拦截到请求:{}",requestURI); //定义不需要处理的请求路径 String[] urls = new String[]{ "/employee/login", "/employee/logout", "/backend/**", "/front/**", "/common/**", "/user/sendMsg", "/user/login" }; //2、判断本次请求是否需要处理 boolean check = check(urls, requestURI); //3、如果不需要处理,则直接放行 if(check){ log.info("本次请求{}不需要处理",requestURI); filterChain.doFilter(request,response); return; } //4、判断登录状态,如果已登录,则直接放行 if(request.getSession().getAttribute("employee") != null){ log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("employee")); Long id = Thread.currentThread().getId(); log.info("线程ID{}",id); BaseContext.setCurrentId((Long) request.getSession().getAttribute("employee")); filterChain.doFilter(request,response); return; } //4-2、判断登录状态,如果已登录,则直接放行 if(request.getSession().getAttribute("user") != null){ log.info("用户已登录,用户id为:{}",request.getSession().getAttribute("user")); Long userId = (Long) request.getSession().getAttribute("user"); BaseContext.setCurrentId(userId); filterChain.doFilter(request,response); return; } log.info("用户未登录"); //5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据 response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN"))); return; } /** * 路径匹配,检查本次请求是否需要放行 * @param urls * @param requestURI * @return */ public boolean check(String[] urls,String requestURI){ for (String url : urls) { boolean match = PATH_MATCHER.match(url, requestURI); if(match){ return true; } } return false; } } 在启动类添加@ServletComponentScan才能扫描过滤器。
@Slf4j //@SpringBootApplication(scanBasePackages={"com.itheima.reggie"}) @SpringBootApplication @ServletComponentScan @EnableTransactionManagement public class ReggieApplication { public static void main(String[] args) { SpringApplication.run(ReggieApplication.class,args); log.info("项目启动成功..."); } }
Gogo科学上网:解锁网络自由的终极指南与深度体验
在信息全球化的今天,互联网本应是无边界的知识海洋,然而地域限制和网络封锁却让许多用户感到困扰。Gogo科学上网作为一款广受欢迎的翻墙工具,通过VPN技术帮助用户突破这些限制,访问被屏蔽的网站与内容。本文将深入探讨Gogo科学上网的使用方法、安装配置技巧,并结合实际体验,分享如何最大化利用这一工具,实现无缝、安全的网络冲浪。
一、Gogo科学上网是什么?为什么选择它?
Gogo科学上网是一款基于虚拟专用网络(VPN)技术的软件,通过加密用户网络连接,将流量路由到境外服务器,从而绕过本地网络监管。它不仅能访问被封锁的社交媒体(如Facebook、YouTube、Twitter)、新闻网站和流媒体平台,还提供了隐私保护功能,防止数据被窃取或监控。
选择Gogo科学上网的理由在于其三大核心优势: - 高强度安全加密:采用AES-256加密协议,确保用户在线活动(如浏览、支付、通信)的隐私性,尤其在公共Wi-Fi环境下能有效防范黑客攻击。 - 高速稳定连接:Gogo拥有全球多节点服务器(包括北美、欧洲、亚洲等),优化线路减少延迟,适合4K流媒体、在线游戏和大文件下载。 - 用户友好设计:界面简洁,一键连接功能让新手也能快速上手,同时支持多设备同步,满足不同场景需求。
二、详细安装与配置步骤
第一步:下载与安装
用户可通过官方渠道(如Gogo官网、Google Play或App Store)下载最新版本,避免第三方平台可能带来的安全风险。下载后,运行安装包,按照提示完成安装(通常需几分钟)。安装过程中,系统可能会请求网络权限或VPN配置授权,用户需点击“允许”以确保正常功能。
第二步:账号注册与登录
首次启动软件时,需进行账号注册。Gogo提供免费试用和付费订阅两种模式:免费版通常有流量或时间限制,适合短期测试;付费版则解锁全部功能,价格根据时长(月付、年付)而异,建议通过官方网站查看最新优惠。注册后,登录账号即可激活服务。
第三步:服务器选择与配置
登录后,主界面会显示服务器列表。用户可根据需求选择: - 地理位置优先:选择离自己较近的服务器(如亚洲节点)以获得更低延迟。 - 功能优化:UDP协议适合游戏和视频流(速度快但可能不稳定),TCP协议更适合浏览和下载(稳定但稍慢)。Gogo还提供“智能匹配”功能,自动选择最佳服务器。
高级设置中,用户可开启“ Kill Switch”(网络中断保护)和“DNS泄漏保护”,进一步提升安全性。这些选项在设置菜单中易于找到,适合对隐私有高要求的用户。
三、使用技巧与心得分享
在实际使用中,我发现Gogo科学上网不仅解决了访问限制问题,还提升了整体网络体验。以下是一些实用心得: - 流媒体优化:观看Netflix或YouTube时,选择美国或欧洲服务器,可解锁地区限定内容。建议避开高峰时段(如晚间),以减少带宽竞争带来的速度下降。 - 多设备同步:Gogo支持Windows、macOS、iOS和Android设备,我通常在电脑和手机上同时安装,通过账号同步设置,实现无缝切换。对于路由器用户,还可配置全局VPN,保护所有连接设备。 - 隐私保护实践:尽管Gogo加密技术可靠,但我仍习惯结合浏览器隐私扩展(如HTTPS Everywhere),并定期清除Cookies,以双重保障数据安全。
常见问题解决: - 若连接失败,首先检查网络状态,尝试切换服务器或协议(如从UDP换为TCP)。 - 速度慢时,可使用Gogo内置的“速度测试”工具筛选最优节点,或联系客服获取线路建议。 - 在中国大陆等严格管控地区,Gogo可能偶尔被干扰,此时更新软件版本或使用“混淆服务器”功能(隐藏VPN流量)往往有效。
四、常见问题解答(FAQ)
Gogo科学上网是否免费?
它提供有限免费试用,但长期使用需付费订阅。付费计划性价比高,且常折扣,建议通过官网购买以避免诈骗。
支持哪些设备?
兼容主流平台,包括PC、Mac、iPhone和Android设备。安装包可直接从官网下载,无需额外配置。
如何取消订阅?
在官网用户中心管理订阅,或通过客服邮件处理。注意免费试用可能自动续费,及时关闭以避免扣款。
是否合法?
在大多数国家,VPN工具合法,但用户需遵守当地法律,勿用于非法活动。Gogo隐私政策明确表示不记录用户日志,进一步降低风险。
五、总结与点评
Gogo科学上网是一款功能全面、易于使用的翻墙工具,它不仅打破了网络边界,还为用户提供了安全、高速的在线环境。通过本文的指南,用户可从下载安装到高级配置,逐步掌握使用技巧,轻松访问全球内容。
从个人体验来看,Gogo在速度和稳定性上表现突出,尤其适合流媒体爱好者和隐私关注者。唯一需要注意的是,在严格网络管控地区可能需要额外设置。总体而言,它是现代数字生活中不可或缺的工具,帮助用户真正实现“网络自由”。
精彩点评:
在信息时代,网络自由不仅是技术问题,更是权利问题。Gogo科学上网如同一把数字钥匙,解锁了被禁锢的认知之门。它的加密技术像一面盾牌,护卫着用户的隐私;它的全球服务器网络则如一座桥梁,连接起文化与知识的分隔。使用Gogo,不仅是技术操作,更是一次对开放精神的践行——让每个人都能平等地拥抱这个世界。然而,用户也需谨记:工具虽强,但理性与合法使用才是长久之道。在畅游无限网络时,不忘尊重规则,方能真正享受科技带来的红利。
通过这份指南,希望您能轻松上手Gogo科学上网,开启无障碍的互联网之旅。如果有更多疑问,欢迎在评论区交流分享!
版权声明:
作者: FreeClashNode
链接: https://www.freeclashnode.com/news/article-1739.htm
来源: www.freeclashnode.com
文章版权归作者所有,未经允许请勿转载。
热门文章
- 6月26日免费节点分享|22.7M/S,Clash节点/V2ray节点/Shadowrocket节点/Singbox节点|免费上网梯子每天更新
- 6月29日免费节点分享|22M/S,V2ray节点/Shadowrocket节点/Clash节点/Singbox节点|免费上网梯子每天更新
- 7月1日免费节点分享|18.1M/S,Shadowrocket节点/V2ray节点/Clash节点/Singbox节点|免费上网梯子每天更新
- 7月3日免费节点分享|22.8M/S,V2ray节点/Clash节点/Shadowrocket节点/Singbox节点|免费上网梯子每天更新
- 6月16日免费节点分享|22.2M/S,V2ray节点/Clash节点/SSR节点/Singbox节点|免费上网梯子每天更新
- 6月30日免费节点分享|18.6M/S,Singbox节点/Clash节点/SSR节点/V2ray节点|免费上网梯子每天更新
- 7月4日免费节点分享|21.6M/S,Singbox节点/SSR节点/Clash节点/V2ray节点|免费上网梯子每天更新
- 6月25日免费节点分享|23M/S,V2ray节点/Shadowrocket节点/Singbox节点/Clash节点|免费上网梯子每天更新
- 6月27日免费节点分享|21.4M/S,V2ray节点/Singbox节点/Clash节点/Shadowrocket节点|免费上网梯子每天更新
- 6月23日免费节点分享|22.4M/S,Shadowrocket节点/V2ray节点/Singbox节点/Clash节点|免费上网梯子每天更新
最新文章
- 全面掌握Shadowrocket安卓账号:从入门到精通的终极指南
- 7月15日免费节点分享|18.2M/S,SSR节点/Clash节点/Singbox节点/V2ray节点|免费上网梯子每天更新
- 如何免费使用v2rayNG:详细教程与实用技巧
- 7月14日免费节点分享|19.6M/S,Shadowrocket节点/V2ray节点/Clash节点/Singbox节点|免费上网梯子每天更新
- v2rayNG 接口全解析:使用、配置与优化指南
- 7月13日免费节点分享|21.1M/S,V2ray节点/Clash节点/Shadowrocket节点/Singbox节点|免费上网梯子每天更新
- 如何解决Quantumult X“无法连接服务器”问题的全面指南
- 7月12日免费节点分享|21.1M/S,Singbox节点/Clash节点/Shadowrocket节点/V2ray节点|免费上网梯子每天更新
- 苹果手机安全上网利器:V2Ray完整配置与使用终极指南
- 7月11日免费节点分享|19.5M/S,SSR节点/V2ray节点/Singbox节点/Clash节点|免费上网梯子每天更新
- 绅士科学上网:全面解析科学上网工具与技巧
- 7月10日免费节点分享|19.3M/S,Clash节点/SSR节点/Singbox节点/V2ray节点|免费上网梯子每天更新
- 移动网络新境界:用V2Ray打造安全高速的手机热点共享方案
- 7月9日免费节点分享|20M/S,SSR节点/Singbox节点/V2ray节点/Clash节点|免费上网梯子每天更新
- 网件科学上网:解锁全球互联网的自由密钥
- 7月8日免费节点分享|20.4M/S,V2ray节点/Clash节点/Singbox节点/SSR节点|免费上网梯子每天更新
- V2Ray连接故障排查全攻略:从入门到精通
- 7月7日免费节点分享|20.6M/S,V2ray节点/SSR节点/Clash节点/Singbox节点|免费上网梯子每天更新
- 深入解析Clash常见使用问题及解决方案:从入门到精通
- 7月6日免费节点分享|20M/S,V2ray节点/Singbox节点/Shadowrocket节点/Clash节点|免费上网梯子每天更新
- 科学上网的隐私困境:我们真的能逃脱监视吗?
- 7月5日免费节点分享|18.8M/S,Clash节点/V2ray节点/Shadowrocket节点/Singbox节点|免费上网梯子每天更新
- 7月4日免费节点分享|21.6M/S,Singbox节点/SSR节点/Clash节点/V2ray节点|免费上网梯子每天更新
- 匡威Clash:当经典遇上叛逆,一场跨越世纪的潮流对话
- 7月3日免费节点分享|22.8M/S,V2ray节点/Clash节点/Shadowrocket节点/Singbox节点|免费上网梯子每天更新
- 科学上网中的UDP加速技术详解
- 7月2日免费节点分享|21.1M/S,Singbox节点/V2ray节点/Clash节点/SSR节点|免费上网梯子每天更新
- Surge3与Quantumult深度对决:功能与性能全面解析与选择指南
- 7月1日免费节点分享|18.1M/S,Shadowrocket节点/V2ray节点/Clash节点/Singbox节点|免费上网梯子每天更新
- 解锁网络自由:GitHub上寻找v2ray免费节点的终极指南
- 6月30日免费节点分享|18.6M/S,Singbox节点/Clash节点/SSR节点/V2ray节点|免费上网梯子每天更新
- 掌控雷霆:全面解析Clash电击作战的精妙战术与实战技巧
- 6月29日免费节点分享|22M/S,V2ray节点/Shadowrocket节点/Clash节点/Singbox节点|免费上网梯子每天更新
- 科学上网:外贸企业突破地域限制、提升全球销售额的数字桥梁
- 6月28日免费节点分享|19.3M/S,Singbox节点/Clash节点/V2ray节点/SSR节点|免费上网梯子每天更新
- 突破网络边界:Windows 10浏览器科学上网全攻略
- 6月27日免费节点分享|21.4M/S,V2ray节点/Singbox节点/Clash节点/Shadowrocket节点|免费上网梯子每天更新
- 深度解析:Shadowrocket连接成功却无数据传输的全面解决方案
- 6月26日免费节点分享|22.7M/S,Clash节点/V2ray节点/Shadowrocket节点/Singbox节点|免费上网梯子每天更新
- 6月25日免费节点分享|23M/S,V2ray节点/Shadowrocket节点/Singbox节点/Clash节点|免费上网梯子每天更新
- 6月24日免费节点分享|18.8M/S,SSR节点/V2ray节点/Singbox节点/Clash节点|免费上网梯子每天更新
- 突破限制:Shadowrocket第三方安装全攻略与深度配置指南
- 6月23日免费节点分享|22.4M/S,Shadowrocket节点/V2ray节点/Singbox节点/Clash节点|免费上网梯子每天更新
- 打开网络新世界的大门:老司科学上网官网54lsj全方位使用指南
- 6月22日免费节点分享|21.7M/S,Clash节点/Singbox节点/Shadowrocket节点/V2ray节点|免费上网梯子每天更新
- Shadowrocket 配置文件添加全攻略:从小白到高手的科学上网实践指南
- 6月21日免费节点分享|19.7M/S,V2ray节点/SSR节点/Clash节点/Singbox节点|免费上网梯子每天更新
- 机顶盒为何难兼容V2ray?深度解析与替代方案全攻略
- 6月20日免费节点分享|20.6M/S,Shadowrocket节点/V2ray节点/Clash节点/Singbox节点|免费上网梯子每天更新
- 突破网络封锁的利器:Shadowsock全方位使用指南与深度解析
归档
- 2026-07 29
- 2026-06 55
- 2026-05 56
- 2026-04 51
- 2026-03 60
- 2026-02 52
- 2026-01 56
- 2025-12 59
- 2025-11 55
- 2025-10 56
- 2025-09 55
- 2025-08 49
- 2025-07 31
- 2025-06 30
- 2025-05 31
- 2025-04 30
- 2025-03 388
- 2025-02 360
- 2025-01 403
- 2024-12 403
- 2024-11 390
- 2024-10 403
- 2024-09 388
- 2024-08 402
- 2024-07 427
- 2024-06 442
- 2024-05 181
- 2024-04 33
- 2024-03 31
- 2024-02 29
- 2024-01 51
- 2023-12 52
- 2023-11 32
- 2023-10 32
- 2023-09 3