JavaWeb学习-Spring全家桶 (三)

静态资源管理

application.properties

spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=classpath:/static/

spring.web.resources.static-locations默认是classpath:/static/,就是这个:

image-20230508181441575

当然你可以自定义

spring.mvc.static-path-pattern 是定义的虚拟路径,没有定义的话默认/,也就是可以直接输入静态资源的文件名来访问spring.web.resources.static-locations里的文件

比如说我这样设置

spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=classpath:/static/

static放了张这样的图

image-20230508181953322

需要这样使用虚拟路径(spring.mvc.static-path-pattern)+文件名才能访问到

image-20230508182016980

文件上传

springboot内置的tomcat默认上传文件最大值10M

application.properties

image-20230508182402868

package com.example.demo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;

@RestController
public class FileUploadController {

    @RequestMapping(value = "/upload",method = RequestMethod.POST)
    public String upload(String nickname, MultipartFile photo, HttpServletRequest request) throws IOException {
        System.out.println(nickname);
        // 文件原始名称
        System.out.println(photo.getOriginalFilename());
        // 文件类型
        System.out.println(photo.getContentType());

        String path = request.getServletContext().getRealPath("/upload/");
        System.out.println(path);
        saveFile(photo,path);

        return "上传成功";
    }

    public void saveFile(MultipartFile photo,String path) throws IOException {
        File dir = new File(path);
        if(!dir.exists()){
            //创建项目
            dir.mkdir();
        }
        File file = new File(path + photo.getOriginalFilename());
        photo.transferTo(file);

    }
}

可以用postman测一测

image-20230508234533320

上传成功

image-20230508234549862

如果想要改变upload前面的路径,可以被用户访问的话,可以在application中修改

spring.mvc.static-path-pattern=/static/**
spring.web.resources.static-locations=/upload/

和之前的静态路径类似,这里是把/upload(注意没加classpath,classpath是src目录下的,没加的情况是在tomcat的环境下)映射到虚拟路径/static

可以看到

image-20230508235352313

成功访问

如果仔细看的话,会发现这个目录其实是一个会变化的目录,所以要多上传几遍,不然找不到图片路径了

image-20230510092223346

这个开发的时候会变,部署服务器后就固定了

如果嫌麻烦可以把这个路径写死

image-20230510092341047

当然学安全的同学都知道写在/tmp目录下是比较符合安全规范的(当然部署程序的时候肯定还得变)

拦截器

功能:

  • 权限检查。检测是否登录了,未登录则返回到登录界面
  • 性能监测。找出某段程序的处理时间
  • 通用行为。读取cookie并将用户对象放入请求

spring boot 定义了 HandlerInterceptor 接口来实现自定义拦截器的功能

preHandle、postHandle、afterCompletion三种方法

image-20230510093725180

请求过来先经过拦截器(preHandle),再到控制器,最后回到拦截器(postHandle),页面渲染的时候也会用到拦截器(afterCompletion)

拦截器

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        System.out.println("LoginInterceptor");
        return true;
    }

}

继承HandlerInterceptor,重写preHandle

但是这样还未失效,我们需要增加配置

package com.example.demo.config;

import com.example.demo.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/user/**");
    }
}

添加配置后生效(必须添加@Configuration并且继承WebMvcConfigurer实现addInterceptors方法)

假如不加上.addPathPatterns("/user/**");的话呢,所有资源都会被其拦截

我把它删去了,试访问一下

image-20230510102957938

拦截成功

image-20230510102932293

restful风格

RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP可以使用 XML 格式定义或 JSON 格式定义。最常用的数据格式是JSON。由于JSON能直接被JavaScript读取,所以,使用JSON格式的REST风格的API具有简单、易读、易用的特点

请求方式 含义
GET(SELECT) 从服务器取出资源(一项或多项)
POST(CREATE) 在服务器新建一个资源
PUT(UPDATE) 在服务器更新资源(更新完整资源)
PATCH(UPDATE) 在服务器更新资源, PATCH更新个别属性
DELETE(DELETE) 从服务器删除资源

其实前面这些都是概念性的东西,下面这个是真正restful和传统uri请求的差异

【1】查询

查询 传统 restful 代码demo
查询所有 http://localhost:8080/employee/list http://localhost:8080/employees @RequestMapping(value = “/employees”, method = RequestMethod.GET)
查询单个 http://localhost:8080/employee/list?id=1 http://localhost:8080/employees/1 @RequestMapping(value = “/employees/{id}”, method = RequestMethod.GET)br/>@ResponseBody
public Employee queryById(@PathVariable Long id) {}

【2】添加

添加 传统 restful 代码demo
添加单个 http://localhost:8080/employee/add http://localhost:8080/employees @RequestMapping(value = “/employees”, method = RequestMethod.POST)
public Employee add(@ModelAttribute(“emp”) Employee employee) {}

【3】修改

添加 传统 restful 代码demo
添加单个 http://localhost:8080/employee/add http://localhost:8080/employees @RequestMapping(value = “/employees”, method = RequestMethod.POST)
public Employee add(@ModelAttribute(“emp”) Employee employee) {}

【4】删除

删除 传统 restful 代码demo
删除单个 http://localhost:8080/employee/delete http://localhost:8080//employees/{id} @RequestMapping(value = “/employees/{id}”, method = RequestMethod.DELETE)br/>@ResponseBody
public JsonResult delete(@PathVariable Long id) {}

注意:
【1】当参数非常多的时候,不建议使用参数路径方式;
【2】如果参数名非常敏感,建议使用参数路径方式,可以隐藏参数名。
原文链接:https://blog.csdn.net/zzvar/article/details/118164133

比如我们写个测试demo

package com.example.demo.controller;

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

@RestController
public class UserController {
    @GetMapping("/user/{id}")
    public String getUserById(@PathVariable int id){
        System.out.println(id);
        return "根据ID获取用户信息";
    }
    @PostMapping("/user")
    public String save(User user){
        return "添加用户";
    }
    @PutMapping("/user")
    public String update(User user){
        return "更新用户";
    }
    public String deleteById(@PathVariable int id){
        System.out.println(id);
        return "根据ID删除用户";
    }

}

get请求一下 http://127.0.0.1:8080/user/123

然后可以用post测一下PUT请求的restful api

我稍微改了一下,打印我传入的参数

image-20230516152422302

随后我们尝试传入

image-20230516152458934

可以看到后端成功的回显了

image-20230516152524608

swagger

就是一个可以通过前端直接调用到相应api的小工具

pom.xml

        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

SwaggerConfig

package com.example.demo.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration   // 告诉spring这是一个配置类
@EnableSwagger2     // 启动swagger的功能

public class SwaggerConfig {

    /**
     * 配置swagger2相关的bean
     * @return
     */
    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com"))
                .paths(PathSelectors.any()).build();
    }

    /**
     * 此处主要是API文档页面的相关显示信息
     */
    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("演示项目API")
                .description("演示项目")
                .version("1.0")
                .build();
    }

}

image-20230516161240038

image-20230516161227132

spring.mvc.pathmatch.matching-strategy=ant_path_matcher

可能是因为版本问题吧,访问 /swagger-ui.html 后404

MyBatis

ORM: 又称为对象关系映射,用于处理数据库交互,orm的本质就是简化编程中操作数据库的编码

java后端 --- orm --- 数据库 (举例就是php的pdo框架,java的MyBatis)

image-20230516170418309

Mybatis

Mybatis是一个优秀的ORM

MybatisPlus

MybatisPlus是基于Mybatis的

建议直接新建一个project再弄

添加依赖

pom.xml

        <!-- MybatisPlus依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
        <!-- 数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.20</version>
        </dependency>

配置项

application.properties

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/数据库名?useSSL=false
spring.datasource.username=root
spring.datasource.password=yourpasswd
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

然后你需要自行建一个mysql及其某某数据表

比如下面

image-20230516222941276

接下来是一个比较复杂的环节orm编程环节,虽然代码量并不大

我们需要创建三个Java文件,其中UserMapper是interface类,其他都是普通类,以下是他的们设计理念

image-20230517150825765

Controller处理用户的路由,然后调用Mapper,Mapper则将mysql返回的数据存储到User这个数据结构,最后通过Controller返回

user

package com.example.demo_mysql.entity;

public class User {
    private int id;
    private String username;
    private String password;
    private String birthday;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday='" + birthday + '\'' +
                '}';
    }
}

这个是一个用于存储数据的数据结构,我们为了规范化数据和减少代码量,写了一个和mysql表的字段一一对应的数据结构(可以alt+insert快速填充get set方法),

image-20230517150343907

UserMapper

package com.example.demo_mysql.Mapper;

import com.example.demo_mysql.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper {
    // 查询所有用户
    @Select("select * from user")
    public List<User> find();

}

image-20230517145608150

UserController

package com.example.demo_mysql.controller;

import com.example.demo_mysql.Mapper.UserMapper;
import com.example.demo_mysql.entity.User;
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;

@RestController
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @GetMapping("/user")
    public String query(){

        List<User> list = userMapper.find();
        System.out.println(list);
        return "查询用户";
    }
}

尝试访问

image-20230516225224133

成功

image-20230516225218529

但是前端往往需要后端返回一个json格式的值,所以需要我们做一些处理:

把controller返回的string修改为list属性

    @GetMapping("/user")
    public List query(){

        List<User> list = userMapper.find();
        System.out.println(list);
        return list;
    }

自动返回

image-20230517172005385

image-20230517172026642

插入

    @Insert("insert into user values(#{id},#{username},#{password},#{birthday})")
    public int insert(User user);
    @PostMapping("/user/save")
    public String save(User user){

        int flag = userMapper.insert(user);
        if(flag > 0){
            return "传输成功";
        }else{
            return "插入失败";
        }

    }

image-20230519173539228

image-20230519173528742

image-20230519173555251

但实际中这个id我们往往把它设置为主键,然后自增,这样的话就可以不用设置插入的id值

MyBatisPlus

简介 | MyBatis-Plus (baomidou.com)

上面演示的MyBatis,这里介绍MyBatisPlus,MyBatisPlus已经写好了一个具备增删查改功能的接口,继承后我们可以减少代码量

继承前 MyBatis

@Mapper
public interface UserMapper {
    // 查询所有用户
    @Select("select * from user")
    public List<User> find();

    @Insert("insert into user values(#{id},#{username},#{password},#{birthday})")
    public int insert(User user);

}

继承后 MyBatisPlus

package com.example.demo_mysql.Mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo_mysql.entity.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper
public interface UserMapper extends BaseMapper<User> {
    // 查询所有用户
//    @Select("select * from user")
//    public List<User> find();
//
//    @Insert("insert into user values(#{id},#{username},#{password},#{birthday})")
//    public int insert(User user);

}

然后controller要注意修改

    @GetMapping("/user")
    public List query(){

        List<User> list = userMapper.selectList(null);
        System.out.println(list);
        return list;
    }

image-20230520154622503

测试一下,成功

image-20230520154551665

这里表名和数据结构的类名要保持一致,(会自动把大写转小写,因为mysql不区分大小写嘛)

如果不一致的话需要注解

注解 | MyBatis-Plus (baomidou.com)

@TableName("sys_user")
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

比如说上面这个User注解了一个@TableName("sys_user"),也就是说传入这个类名就会自动转为为与sys_user相关的操作

我们再试试插入

由于前面咱是没有设置主键和自增的,那么插入的时候没填写id就会乱,而用户又不可能知道id值,无法传输给后端,所以我们可以使用一个注解(注解 | MyBatis-Plus (baomidou.com)

    @TableId(type = IdType.AUTO)

完整数据结构如下

package com.example.demo_mysql.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;

public class User {

    @TableId(type = IdType.AUTO)
    private int id;
    private String username;
    private String password;
    private String birthday;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday='" + birthday + '\'' +
                '}';
    }
}

不过后面研究一下,发现单独设置注解--自增的话,数据表如果本身不自增也是无效的

image-20230520160431179

所以我勾选了一下auto_increase,所以现在这个表是这样

image-20230520160721051

image-20230520160837281

然后我们再测试一下

image-20230520160926017

image-20230520160945441

image-20230520161001915

测试成功

有个细节:假如你使用了MyBatisPlus,并且数据表id自增的话,你若不传id进来,就必须设置注解IDtype.auto,否则id是0

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇