目录
软件开发整体介绍
软件开发流程
- 需求分析 ⇒ 设计 ⇒ 编码 ⇒ 测试 ⇒ 上线运维
角色分工
- 项目经理:对整个项目负责,任务分配,把控进度。
- 产品经理:进行需求分析,输出需求调研文档,产品原型等。
- UI设计师:根据产品原型输出界面效果图。
- 架构师:项目整体架构设计,技术选型等。
- 开发工程师:代码实现。
- 测试工程师:编写测试用例,输出测试报告。
- 运维工程师:软件环境搭建,项目上线。
软件环境
- 开发环境(development):开发人员在开发阶段使用的环境,一般外部用户无法访问。
- 测试环境(testing):专门给测试人员使用的环境,用于测试项目,一般外部用户无法访问。
- 生产环境(production):即线上环境,正式提供对外服务的环境。
瑞吉外卖项目介绍
项目介绍
产品原型
- 产品原型,就是一款产品成型之前的一个简单的框架,就是将页面的排版布局展现出来,使产品的初步构思有一个可
视化的展示。通过原型展示,可以更加直观的了解项目的需求和提供的功能。 - 注意:产品原型主要用于展示项目的功能,并不是最终的页面效果。
技术选型
功能架构
角色
- 后台系统管理员:登录后台管理系统,拥有后台系统中的所有操作权限。
- 后台系统普通员工:登录后台管理系统,对菜品、套餐、订单等进行管理。
- C端用户:登录移动端应用,可以浏览菜品、添加购物车、设置地址、在线下单等。
开发环境搭建
数据库环境搭建
- 创建数据库
- 导入表(命令行导入路径必须全英文)
maven项目搭建
1.创建maven项目
2.创建完毕后一定要检查项目的编码、maven仓库的配置、jdk配置等。
3.导入pom文件。
<?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>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<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>
<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>
</build>
</project>
4.导入配置文件 application.yml
server:
port: 8080
spring:
application:
# 项目名称,可选
name: reggie_take_out
datasource:
druid:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3307/reggie?useSSL=false&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
mybatis-plus:
configuration:
#在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: ASSIGN_ID
5.编写启动类
package com.itheima.reggie;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@Slf4j
@SpringBootApplication
public class ReggieApplication {
public static void main(String[] args) {
SpringApplication.run(ReggieApplication.class, args);
log.info("项目启动成功~");
}
}
6.设置静态资源映射(根目录下建包config,创建WebMvcConfig extends WebMvcConfigurationSupport)
package com.itheima.reggie.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@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/");
}
}
后台登陆功能开发
需求分析
- 参照产品原型进行开发(controller⇒ service⇒ mapper⇒ DB)
代码开发
包结构:
1.创建实体类(根目录下建包entity,创建Employee类)
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;
/**
* employee实体类
*/
@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;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@TableField(fill = FieldFill.INSERT)
private Long createUser;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updateUser;
}
2.创建mapper映射文件(根目录下建包mapper,创建EmployeeMapper类)
package com.itheima.reggie.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.reggie.entity.Employee;
import org.apache.ibatis.annotations.Mapper;
/**
* @author Mv
* @date 2022/12/30 14:06
*/
@Mapper
public interface EmployeeMapper extends BaseMapper<Employee> {
}
3.创建controller(根目录下建包controller,创建EmployeeController类)
package com.itheima.reggie.controller;
import com.itheima.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Mv
* @date 2022/12/30 14:13
*/
@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
}
4.创建service
package com.itheima.reggie.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* @author Mv
* @date 2022/12/30 14:13
*/
@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);
}
}
5.导入通用返回结果类R
package com.itheima.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;
}
}
功能测试
完善登录功能
问题分析
代码实现
package com.itheima.reggie.filter;
import com.alibaba.fastjson.JSON;
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;
/**
* @author Mv
* @date 2022/12/31 10:29
* 检查用户是否完成登录
*/
@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();
log.info("拦截到的请求是:{}",requestURI);
// 定义不需要处理的请求路径
String[] urls = new String[]{
"/employee/login",
"/employee/logout",
"/backend/**",
"/front/**"
};
//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"));
filterChain.doFilter(request, response);
return;
}
log.info("用户未登录");
//5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
return;
}
private boolean check(String[] urls, String requestURI) {
for (String url : urls) {
boolean match = PATH_MATCHER.match(url, requestURI);
if(match) {
return true;
}
}
return false;
}
}
后台退出功能开发
需求分析
- 员工登录成功后,页面跳转到后台系统首页面(backend/index.html),此时会显示当前登录用户的姓名,如果员工需要退出系统,直接点击右侧的退出按钮即可退出系统,退出系统后页面应跳转回登录页面。
代码开发
用户点击页面中退出按钮,发送请求,请求地址为/employee/八ogout,请求方式为POST。我们只需要在Controller中创建对应的处理方法即可,具体的处理逻辑:
1、清理Session中的用户id
2、返回结果
/**
* 员工退出
* @param request
* @return
*/
@PostMapping("/logout")
public R<String> logout(HttpServletRequest request) {
// 清理session中保存的当前员工的id
request.getSession().removeAttribute("employee");
return R.success("退出成功");
}