javaweb案例

准备工作

idea中alt+enter快速生成方法

查询端口占用情况

cmd中netstat -ano | findstr :8080找到pid最后在任务管理器中结束该项目

部门管理

需求,环境搭建

准备数据库表(dept,emp)

-- 创建新的部门表
CREATE TABLE dept
(
    id             INT PRIMARY KEY AUTO_INCREMENT,
    name           VARCHAR(10) NOT NULL,
    operation_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -- 操作时间字段
);
-- 插入部门信息
INSERT INTO dept (name)
VALUES ('人力资源部'),
       ('财务部'),
       ('市场部'),
       ('研发部'),
       ('销售部');
-- 创建新的员工表
CREATE TABLE emp
(
    id             INT PRIMARY KEY AUTO_INCREMENT,
    name           VARCHAR(20) NOT NULL,
    password       varchar(32) default '123456',
    position       VARCHAR(50),
    dept_id        INT,
    photo          varchar(300),                                                     -- 图片字段,使用BLOB类型存储二进制数据
    gender         tinyint,                                                          -- 性别字段,1男  2女
    date           DATE,                                                             -- 入职日期字段
    operation_time TIMESTAMP   DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -- 操作时间字段
);
INSERT INTO emp (name, position, dept_id, photo, gender, date)
VALUES ('张三', '经理', 1, NULL, 1, '2020-01-15')
     , ('李四', '会计', 2, NULL, 2, '2019-05-20')
     , ('王五', '市场专员', 3, NULL, 1, '2021-03-10')
     , ('赵六', '软件工程师', 4, NULL, 1, '2018-11-05')
     , ('孙七', '销售代表', 5, NULL, 2, '2022-02-28')
     , ('周八', '人力资源专员', 1, NULL, 2, '2020-06-12')
     , ('吴九', '财务分析师', 2, NULL, 2, '2019-09-30')
     , ('郑十', '市场经理', 3, NULL, 1, '2021-07-25')
     , ('冯十一', '高级软件工程师', 4, NULL, 1, '2018-04-18')
     , ('陈十二', '销售经理', 5, NULL, 2, '2022-01-03');

创建springboot工程,引入对应的起步依赖(web,mybatis,mysql驱动,lombok)

配置application.properties中引入mybatis的配置信息,准备对应的实体类

spring.application.name=studylearn

#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/studylearn
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=123456

#配置mybatis的日志,指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#开启mybatis的驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true
#pojo中emp实体类
package com.example.studylearn.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer id;
    private String name;
    private String password;
    private Short gender;
    private String photo;
    private Integer deptid;
    private Short position;
    private LocalDate date;
    private LocalDateTime operationtime;
}
#pojo中dept实体类
package com.example.studylearn.pojo;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dept {
    private Integer id;
    private String name;
    private LocalDateTime operationtime;
}

准备对应的mapper,service(接口,实现类),controller基础结构

#service接口和类
package com.example.studylearn.service.impl;

import com.example.studylearn.service.DeptService;
import org.springframework.stereotype.Service;

@Service
public class DeptServiceImpl implements DeptService {
}
package com.example.studylearn.service;

public interface DeptService {
}
#pojo中实体类
package com.example.studylearn.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    private Integer id;
    private String name;
    private String password;
    private Short gender;
    private String photo;
    private Integer deptid;
    private Short position;
    private LocalDate date;
    private LocalDateTime operationtime;
}
#mapper中接口
package com.example.studylearn.mapper;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface EmpController {
}
#controller中类
package com.example.studylearn.controller;

import org.springframework.web.bind.annotation.RestController;

@RestController
public class DeptController {

}

开发规范restful

representational state transfer ,表述性状态转换,它是一种软件架构风格

pojo中实体类result

package com.example.studylearn.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result {
    private Integer code;//响应吗:1成功,0失败
    private String msg;//响应信息 描述字符串
    private Object data;//返回的数据

    //增删改 成功响应
    public static Result success() {
        return new Result (1,"success", null);
    }
    //查询 成功响应
    public static Result success(Object data) {
        return new Result(1,"success",data);
    }
    //失败响应
    public static Result error(String msg) {
        return new Result(0, msg,null);
    }
}

如果出错可能是pox.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 https://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>3.3.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>studylearn</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>studylearn</name>
    <description>Demo project for Spring Boot</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>22</java.version>
    </properties>
    <dependencies>
<!--        web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--        mybatis起步依赖-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
<!--mysql驱动-->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>3.0.3</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

流程

部门查询

controller层代码

package com.example.learn_system.controller;

import com.example.learn_system.pojo.Dept;
import com.example.learn_system.pojo.Result;
import com.example.learn_system.service.DeptService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@Slf4j
@RestController
public class DeptController {

    @Autowired
    private DeptService deptService;

//    @RequestMapping(value = "/depts",method = RequestMethod.GET )
    @GetMapping("/depts")
    public Result list(){
        log.info("查询全部部门数据");
        //调用service查询部门数据
        List<Dept> deptList=deptService.list();
        return Result.success(deptList);
    }

}

dept接口方法 service

package com.example.learn_system.service;

import com.example.learn_system.pojo.Dept;

import java.util.List;

public interface DeptService {
    /*查询全部部门数据*/
    List<Dept> list();
}

deptservice实现类

package com.example.learn_system.service.impl;

import com.example.learn_system.mapper.DeptMapper;
import com.example.learn_system.pojo.Dept;
import com.example.learn_system.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DeptServiceImpl implements DeptService {

    @Autowired
    private DeptMapper deptMapper;

    @Override
    public List<Dept> list(){
        return deptMapper.list();
    }
}

dept mapper操作数据库

package com.example.learn_system.mapper;

import com.example.learn_system.pojo.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface DeptMapper {
    /*查询全部部门*/
    @Select("select * from dept")
    List<Dept> list();
}

前后端联调

部署nginx把部署的nginx启动

访问http://local:90

删除部门

//controller 中
    /*删除部门*/
    @DeleteMapping("/depts/{id}")
    public Result delete(@PathVariable Integer id){
        log.info("根据id删除部门,{}",id);
        //调用service删除部门
        deptService.delete(id);
        return Result.success();
    }
//service接口
//    删除部门
    void delete(Integer id);
//service实现类
   @Override
    public void delete(Integer id) {
        deptMapper.deleteById(id);
    }
//mapper接口操作数据库
//    根据id删除部门
    @Delete("delete from dept where id = #{id}")
    void deleteById(Integer id);

新增部门

//controller层
//    新增部门
    @PostMapping("/depts")
    public Result add(@RequestBody Dept dept){
        log.info("新增部门{}",dept);
        //调用service新增部门
        deptService.add(dept);
        return Result.success();
    }
//service接口
//新增部门
    void add(Dept dept);
//service实现类
    @Override
    public void add(Dept dept) {
        dept.setOperationTime(LocalDateTime.now());
        deptMapper.insert(dept);
    }
//mapper
 //新增部门
    @Insert("insert into dept(name ,operation_time) value (#{name},#{operationTime})")
    void insert(Dept dept);

优化

员工管理

分页查询

原始方法

//pojo中首先新建实体类
/*分页查询结果封装类*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageBean {
    private Long total;//总记录数
    private List rows;//数据列表
}
//emp   mapper中
//    查询总记录数
    @Select("select count(*) from emp")
    public Long count();
//    分页查询,获取列表数据
    @Select("select * from emp limit #{start},#{pageSize}")
    public List<Emp> page(Integer start, Integer pageSize)
//emp中controller
@Autowired
    private EmpService empService;

    @GetMapping("/emps")
    public Result page(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue ="10") Integer pageSize) {
        log.info("分页查询,参数{},{}", page, pageSize);
        //调用service分页查询
        PageBean pageBean = empService.page(page, pageSize);
        return Result.success(pageBean);
    }
//emp的serverce接口
public interface EmpService {
    PageBean page(Integer page, Integer pageSize);
}
//emp的service
  @Autowired
    private EmpMapper empMapper;
    @Override
    public PageBean page(Integer page, Integer pageSize) {
        //获取总记录数
        Long count=empMapper.count();
        //获取分页查询结果列表
        Integer start=(page-1)*pageSize;
        List<Emp> empList=empMapper.page(start,pageSize);
        //封装PageBean对象
        PageBean pageBean=new PageBean(count,empList);
        return pageBean;
    }

分页插件PageHelper

//pom.xml中
<!--pagehelper分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.2</version>
        </dependency>
//empmapper中接口信息
//    员工信息的查询
    @Select("select * from emp")
    public List<Emp> list();
//empservice中
    @Override
    public PageBean page(Integer page, Integer pageSize) {
       //设置分页参数
        PageHelper.startPage(page,pageSize);
        //执行查询
        List<Emp> empList = empMapper.list();
        Page<Emp> p=(Page<Emp>) empList;
        //封装PageBean对象
        PageBean pageBean = new PageBean(p.getTotal(), p.getResult());
        return pageBean;
    }
//其余的不变

分页查询(待条件)

//empcontroller层
  @Autowired
    private EmpService empService;

    @GetMapping("/emps")
    public Result page(@RequestParam(defaultValue = "1") Integer page,
                       @RequestParam(defaultValue = "5") Integer pageSize,
                       String name, Short gender,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate begin,
                       @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate end) {
        log.info("分页查询,参数{},{},{},{},{},{}", page, pageSize,name,gender,begin,end);
        //调用service分页查询
         PageBean pageBean = empService.page(page, pageSize,name,gender,  begin, end);
        return Result.success(pageBean);
//empservice接口
PageBean page(Integer page, Integer pageSize, String name, Short gender, LocalDate begin,LocalDate end);
//empservice类中
List<Emp> empList = empMapper.list(name, gender, begin, end);

多条件查询需要用到xml

resources中新建empmapper的.xml文件(同包同名)

//mapper接口
public interface EmpMapper {
    public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
}
//EmpMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace路径与EmpMapper接口类path一致-->
<mapper namespace="com.example.learn_system.mapper.EmpMapper">
    <!--id与mapper接口的方法名一致
    resultType为单条记录所返回的类型
    -->
    <select id="list" resultType="com.example.learn_system.pojo.Emp">
        select * free emp
        -- where判断是否生成where和and和or子句
        <where>
            <if test="name !=null and name !=''">
                name like concat('%',#{name},'%')
            </if>
            <if test="gender !=null">
                and gender=#{gender}
            </if>
            <if test="begin!=null and end!=null">
                and date between #{begin} and #{end}
            </if>
        </where>
        order by date desc 
    </select>
</mapper>

删除员工

//controller
@DeleteMapping("/{ids}")
    public Result delete(@PathVariable List<Integer> ids){
        log.info("批量删除操作,ids:{}",ids);
        empService.delete(ids);
        return Result.success();
    }
//service接口
void delete(List<Integer> ids);
//service实现类
 @Override
    public void delete(List<Integer> ids) {
        empMapper.delete(ids);
    }
//mapper接口
  //批量删除
    void delete(List<Integer> ids);
//mapper.xml映射文件
 <!--    皮批量删除  (1,2,3)  collection里的是集合名-->
    <delete id="delete">
        delete from emp
        where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </delete>

新增员工

//controller
 @PostMapping
    public Result save(@RequestBody Emp emp){
        log.info("新增员工,emp:{}",emp);
        empService.save(emp);
        return Result.success();
    }
//service接口
void save(Emp emp);
//service实现类
 @Override
    public void save(Emp emp) {
        emp.setDate(LocalDateTime.now());
        emp.setOperationTime(LocalDateTime.now());
        empMapper.insert(emp);
    }
//mapper接口
@Insert("insert into emp(name, password, position,dept_id,photo, gender, date) " +
            "value (#{name},#{password},#{position},#{deptId},#{photo},#{gender},#{date})")
    void insert(Emp emp);

文件上传

简介

文件上传,是指将本地图片视频,音频等文件上传到服务器,供其他用户浏览或下载的过程

        前端和service控制层  上传文件  的   名字必须要一致

本地存储

服务端,接收到上传上来的文件之后,将文件存储在本地服务器磁盘中

在springboot中,文件上传,默认单个文件允许最大大小为1M。如果需要上传大文件,可以如下配置

//application.properties中设置(在resources中)
#配置单个文件上传大小限制
spring.servlet.multipart.max-file-size=10MB
#配置单个请求最大大小的限制(一次请求中是可以上传多个文件的)
spring.servlet.multipart.max-request-size=100MB
//controller层
@Slf4j
@RestController
public class UploadController {
    @PostMapping("/upload")
    public Result upload(String name, MultipartFile photo) throws IOException {
        log.info("文件上传:{},{}",name,photo);
        //获取原始文件名
        String originalFilename = photo.getOriginalFilename();
        //构造唯一的文件名(不能重复)  --uuid(通用唯一识别码)
        int index = originalFilename.lastIndexOf(".");
        String extname = originalFilename.substring(index);
        String newFileName=UUID.randomUUID().toString()+extname;
        log.info("新的文件名:{}",newFileName);
        //将文件存储在服务器的磁盘目录中E:\javaweb\photo
        photo.transferTo(new File("E:\\javaweb\\photo\\"+newFileName));
        return Result.success();
    }
}

阿里云OSS  使用步骤

object storage service是一款海量,安全,成本低,高可靠的云存储服务。使用oss可通过网络随时存储和调用包括文本,图片,音频,视频等各种文件

bucket:存储空间是用户用于存储对象(object就是文件)的容器,所有的对象都必须隶属于某个存储空间

SDK:software Development Kit的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包),代码实例等,都可以叫做SDK

        点开阿里云中oss服务下载sdk,点开文档操作在pom.xml中配置

        在学习文档中找方法写入,注意修改内容

      // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-beijing.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "examplebucket";
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = "exampledir/exampleobject.txt";
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
        String filePath= "D:\\localpath\\examplefile.txt";

案例集成OSS

引入阿里云oss上传文件工具类(官方代码改造而来)

上传图片接口开发

编辑员工

查询回显

//controller
  @GetMapping("/{id}")
    public Result getById(@PathVariable Integer id){
        log.info("根据id查询员工信息,id:{}",id);
        Emp emp=empService.getById(id);
        return Result.success(emp);
    }
//service接口
 Emp getById(Integer id);
//service实现类
  @Override
    public Emp getById(Integer id) {
        return empMapper.getById(id);
    }
//mapper接口方法
@Select("select * from emp where id-#{id}") 
    Emp getById(Integer id);

修改员工

//controller层
@PostMapping
    public Result update(@RequestBody Emp emp){
        log.info("更新员工:{}",emp);
        empService.update(emp);
        return Result.success();
//service接口
void update(Emp emp);
//service实体类
@Override
    public void update(Emp emp) {
        emp.setOperationTime(LocalDateTime.now());
        empMapper.update(emp);
    }
//mapper文件
void update(Emp emp);
//xml文件放在resource文件新建的包下
    <update id="update">
        update emp
        <set>
            <if test="name !=null and name !=''">
                name=#{name},
            </if>
            <if test="password !=null and password !=''">
                password=#{password},
            </if>
            <if test="position !=null and position !=''">
                position=#{position},
            </if>
            <if test="deptId !=null">
                dept_id=#{deptId},
            </if>
            <if test="photo !=null and photo !=''">
                photo=#{photo},
            </if>
            <if test="gender !=null">
                gender=#{gender},
            </if>
            <if test="date !=null and date !=''">
                date=#{date}
            </if>
        </set>
        where id =#{id}
    </update>

配置文件

参数配置化

yml配置文件

配置格式

yml基本语法

大小写敏感

数之前必须有空格,作为分隔符

使用缩进表示层级关系,缩进时,不允许使用tab,只能用空格(idea中会自动将tab转化为空格)

缩进的空格数目不重要,只要相同层级的元素左侧对齐即可

#表示注释,从这个字符一直到行尾,都会被解析器忽略

#resources文件中新建application.yml的file
#对象/Map集合:
user:
  name: zhangsan
  age: 12
  password: 123456
#数组/List/Set集合
hobby:
  - java
  - game

#例子
spring:
  #数据库连接信息
  datasource:
    #驱动类名称
    driver-class-name: com.mysql.cj.jdbc.Driver
    #数据库连接的url
    url: jdbc:mysql://localhost:3306/study_system
    #连接数据库的用户名
    username: root
    #连接数据库的密码
    password: 123456
  servlet:
    multipart:
      #配置单个文件上传大小限制
      max-file-size: 10MB
      #配置单个请求最大大小的限制(一次请求中是可以上传多个文件的)
      max-request-size: 100MB
mybatis:
  configuration:
    #配置mybatis的日志,指定输出到控制台
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    #开启mybatis的驼峰命名自动映射开关
    map-underscore-to-camel-case: true

#阿里云OSS
aliyun:
  oss:
    emdpoint:
      
  - sport

@ConfigurationProperties

@ConfigurationProperties与@Value

相同点:都是用来注入外部配置的属性的

不同点:@Value注解只能一个一个的进行外部属性的注入

                @ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中

登录功能

//controller曾新建方法
@Slf4j
@RestController
public class LoginController {
    @Autowired
    private EmpService empService;
    public Result login(@RequestBody Emp emp){
        log.info("员工登录:{}",emp);
        Emp e=empService.login(emp);
        return e !=null?Result.success():Result.error("用户名或密码错误");
    }
}
//service接口
Emp login(Emp emp);
//service实现类
 @Override
    public Emp login(Emp emp) {
        return empMapper.getByNameAndPassword(emp);
    }
//mapper接口
@Select("select * from emp where name=#{name} and password =#{password}")
    Emp getByNameAndPassword(Emp emp);

登录校验

会话技术

会话:

用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。再一次会话中可以包含  多次  请求和响应

会话跟踪

一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间        共享数据

会话跟踪方案:

客户端会话跟踪技术:Cookie

@Slf4j
@RestController
public class SessionController {
    //设置cookie
    @GetMapping("/c1")
    public Result cookie1(HttpServletResponse response){
        response.addCookie(new Cookie("login_name","itheima"));
        return Result.success();
    }
    //获取cookie
    @GetMapping("/c2")
    public Result cookie2(HttpServletRequest request){
        Cookie[] cookies= request.getCookies();//获取所有的cookie
        for (Cookie cookie:cookies){
            if (cookie.getName().equals("login_name")){
                //输出那么为login_name的cookie
                System.out.println("login_name:"+cookie.getValue());
            }
        }
        return Result.success();
    }
}
服务端会话跟踪技术:Session

//在HttpSession中存储值
    @GetMapping("/s1")
    public Result session1(HttpSession session){
        log.info("HttpSession-s1:{}",session.hashCode());
        session.setAttribute("loginUser","tom");//session中存储数据
        return Result.success();
    }
    //从httpsession中获取值
    
    public Result session2(HttpServletRequest request){
        HttpSession session=request.getSession();
        log.info("HttpSession-s2:{}",session.hashCode());
        Object loginUser=session.getAttribute("loginUser");//从session中获取数据
        log.info("loginUser:{}",loginUser);
        return Result.success(loginUser);
    }
令牌技术

JWT令牌

简介

一般用于登陆后产生令牌返回浏览器,之后每次请求都会携带令牌去校验,成功后通过

jwt生成(入门)

//pom.xml文件中引入
<!--        JWT令牌-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>
//JWT令牌生成与解析
//    生成JWT
    @Test
    public void testGenJwt(){
        Map<String, Object> claims=new HashMap<>();
        claims.put("id",1);
        claims.put("name","tom");
        String jwt=Jwts.builder()
                .signWith(SignatureAlgorithm.ES256,"itheima")//签名算法
                .setClaims(claims)//自定义内容(载荷)
                .setExpiration(new Date(System.currentTimeMillis()+3600*1000))//设置有效期1h
                .compact();
        System.out.println(jwt);
    }

//    解析jwt

    @Test
    public void testParseJwt(){
        Claims claims=Jwts.parser()
                .setSigningKey("itheima")
                .parseClaimsJws("")//里面填要解析的加密令牌
                .getBody();
        System.out.println(claims);
    }

登录-生成令牌

//java中引入令牌操作工具类
public class JwtUtils {
    private static String signKey="itheima";
    private static Long expire=43200000L;
    //    生成JWT令牌  claims jwt第二部分负载 payload 中存储的内容
    public static String generateJwt(Map<String, Object> claims){
        String jwt= Jwts.builder()
                .addClaims(claims)
                .signWith(SignatureAlgorithm.ES256,signKey)//签名算法
                .setExpiration(new Date(System.currentTimeMillis()+expire))//设置有效期1h
                .compact();
        return jwt;
    }

//    解析jwt令牌  jwt第二部分负载 payload 中存储的内容


    public static Claims ParseJwt(String jwt){
        Claims claims=Jwts.parser()
                .setSigningKey(signKey)
                .parseClaimsJws(jwt)//里面填要解析的加密令牌
                .getBody();
        return claims;
    }
}
//登陆完成后,调用工具类生成JWT令牌,并返回  login类
@Slf4j
@RestController
public class LoginController {
    @Autowired
    private EmpService empService;
    public Result login(@RequestBody Emp emp){
        log.info("员工登录:{}",emp);
        Emp e=empService.login(emp);
        //登陆成功,生成令牌,下发令牌
        if (e!=null){
            Map<String, Object> claims=new HashMap<>();
            claims.put("id",e.getId());
            claims.put("name",e.getName());
            String jwt = JwtUtils.generateJwt(claims);//jwt包含了当前登录的员工信息
            return Result.success(jwt);
        }
        //登陆失败,返回错误信息
        return Result.error("用户名或密码错误");
    }
}

过滤器Filter

快速入门

//新建的实现类
@WebFilter(urlPatterns = "/*")//拦截所有路径
public class DemoFilter implements Filter {
    @Override//初始化方法,只调用一次
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init初始化方法执行了");
    }
    @Override//拦截到请求之后调用,调用多次
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("拦截到了请求");
            //放行
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override//销毁方法,只调用一次
    public void destroy() {
        System.out.println("destroy销毁方法执行了");
    }
}
//springboot启动类上加入
@ServletComponentScan//开启了对servlet组件的支持

详解(执行流程,拦截路径,过滤器链)

拦截路径:

filter可以根据需求,配置不同的拦截资源路径

拦截具体路径        urlPatterns值  /login        只有访问/login路径时,才会被拦截

目录拦截       urlPatterns值/emps/*        访问/emps下的所有资源,都会被拦截

拦截所有        urlPatterns值  /*        访问所有资源,都会被拦截

过滤器链

登录校验-Filter

//filter中
@Slf4j
@WebFilter(urlPatterns = "/*")
public class LoginCheckFilter implements Filter{
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest req=(HttpServletRequest) servletRequest;
        HttpServletResponse resp=(HttpServletResponse) servletResponse;
        //获取请求url
        String url = req.getRequestURL().toString();
        log.info("请求的url:{}",url);
        //判断请求url中是否包含login,若包含,说明是登陆操作,放行
        if (url.contains("login")){
            log.info("登陆操作,放行。。。");
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        //获取请求头中的令牌(token)
        String jwt = req.getHeader("token");
        //判断令牌是否存在,若不存在,返回错误结果(未登录)
        if (!StringUtils.hasLength(jwt)){
            log.info("请求头token为空,返回未登陆的信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换  对象json  ---》阿里巴巴fastJSON  去pom.xml文件配置
            String notLogin= JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }
        //解析token,若解析失败,返回错误结果(未登录)
        try{
            JwtUtils.ParseJwt(jwt);
        }catch(Exception e){//jwt解析失败
            e.printStackTrace();
            log.info("解析令牌失败,返回未登陆错误信息");
            Result error=Result.error("NOT_LOGIN");
            //手动转换  对象json  ---》阿里巴巴fastJSON
            String notLogin= JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return;
        }
        //放行
        log.info("令牌合法,放行");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
//pom.xml文件
<!--        fastJSON-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastJSON</artifactId>
            <version>1.2.76</version>
        </dependency>

拦截器Interceptor

简介        快速入门

概念:是一种动态拦截方法调用的机制,类似于过滤器。spring框架中提供的,用来动态拦截控制器方法的执行

作用:拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码(跟过滤器类似)

//定义拦截器,实现HandlerInterceptor接口,并重写其所有方法  
//新建包和方法
@Component
public class LoginCheckInterceptor implements HandlerInterceptor {//ctrl+o快速创建方法

    @Override//目标资源方法运行前运行,返回true,放行。返回false,不放行
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle ...");
        return true;
    }

    @Override//目标资源方法运行后运行
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle ...");
    }

    @Override//视图渲染完毕后运行,最后运行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion ...");
    }
}
//注册拦截器
@Configuration//配置类
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginCheckInterceptor loginCheckInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginCheckInterceptor).addPathPatterns("/**");
    }
}

详解

拦截路径

执行流程

登录校验  -interceptor

@Component
@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {//ctrl+o快速创建方法

    @Override//目标资源方法运行前运行,返回true,放行。返回false,不放行
    public boolean preHandle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws Exception {
        //获取请求url
        String url = req.getRequestURL().toString();
        log.info("请求的url:{}",url);
        //判断请求url中是否包含login,若包含,说明是登陆操作,放行
        if (url.contains("login")){
            log.info("登陆操作,放行。。。");
            return true;
        }
        //获取请求头中的令牌(token)
        String jwt = req.getHeader("token");
        //判断令牌是否存在,若不存在,返回错误结果(未登录)
        if (!StringUtils.hasLength(jwt)){
            log.info("请求头token为空,返回未登陆的信息");
            Result error = Result.error("NOT_LOGIN");
            //手动转换  对象json  ---》阿里巴巴fastJSON  去pom.xml文件配置
            String notLogin= JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return false;
        }
        //解析token,若解析失败,返回错误结果(未登录)
        try{
            JwtUtils.ParseJwt(jwt);
        }catch(Exception e){//jwt解析失败
            e.printStackTrace();
            log.info("解析令牌失败,返回未登陆错误信息");
            Result error=Result.error("NOT_LOGIN");
            //手动转换  对象json  ---》阿里巴巴fastJSON
            String notLogin= JSONObject.toJSONString(error);
            resp.getWriter().write(notLogin);
            return false;
        }
        //放行
        log.info("令牌合法,放行");
        return true;
    }

异常处理

全局异常处理器

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)  //捕获所有异常
    public Result ex(Exception ex){
        ex.printStackTrace();
        return Result.error("对不起,操作失败,请联系管理员");
    }
}
  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于以上引用内容,我可以为您提供以下答案: 基于JavaWeb的实战项目和案例有很多种,其中包括了在线商城系统、学生管理系统、图书管理系统等。例如,可以采用MVC的设计模式,使用Java Web Servlet和MySQL来实现一个简单的增删改查的功能,同时还可以实现模糊查询和导出Excel表格数据等功能。这样的项目可以作为计算机毕设或课程设计,可以在CSDN等网站上找到相关案例和源码,如引用和引用中提到的案例。 如果您需要更具体的信息,可以参考引用提供的链接,其中有关于JavaWeb案例的更详细的介绍和实现步骤。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java web 实战项目案例](https://blog.csdn.net/liqz666/article/details/95448183)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [计算机毕设课设-基于JavaWeb+SSM+MySQL的在线商城系统.zip](https://download.csdn.net/download/qq_53122658/88218023)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值