【Java代码审计 | 第十五篇】客户端交互流程、注解及函数概念详解

未经许可,不得转载。

在这里插入图片描述

客户端服务端交互流程

在Java Web应用中,URL请求流程是客户端与服务器之间交互的核心过程。它描述了从用户发起请求到服务器返回响应的完整生命周期。

客户端服务端交互的全流程如下。

1、用户发起请求。

2、浏览器将域名解析为服务器的IP地址。

3、浏览器通过TCP协议与服务器建立连接。

4、浏览器将请求信息(如URL、请求头、请求体等)打包成HTTP请求报文,发送到服务器。

5、服务器接收到HTTP请求后,将其解析为Java对象(如HttpServletRequest)。

接着,请求到达MVC(Model-View-Controller)架构。

在这里插入图片描述

在后端,请求的处理流程如下:

1、请求首先经过过滤器(Filter)和拦截器(Interceptor),用于执行一些全局操作,如权限验证、日志记录、字符编码设置等。

2、根据请求的URL映射到对应的控制器方法。

3、控制器方法接收请求参数,调用服务层(Service)处理业务逻辑。

4、服务层通常由接口和实现类组成。控制器调用服务接口,而具体的业务逻辑由ServiceImpl实现类完成。

5、如果业务逻辑涉及数据库操作,服务层会调用数据访问层(DAO)。DAO层负责与数据库交互,执行增删改查等操作。

注意:DAO层只是一个中间传递角色,它不包含业务逻辑,只负责数据的存取。

6、控制器将处理结果封装为模型数据(Model),并传递给视图解析器(ViewResolver)。

7、视图解析器根据逻辑视图名称找到对应的视图模板(如JSP、Thymeleaf等)。

8、视图模板使用模型数据生成最终的HTML页面。

注解

@Controller 注解

作用:标注该类为控制器类,用于处理HTTP请求。

使用场景:

  • 传统的MVC项目中,@Controller通常与视图模板(如JSP、Thymeleaf)配合使用,返回视图名称。

  • 在现代前后端分离的项目中,后端通常返回JSON数据,此时@Controller可以结合@ResponseBody使用。

@ResponseBody 注解

作用:将方法的返回值直接写入HTTP响应体中,通常用于返回JSON或XML格式的数据。

使用场景:

  • 前后端分离的项目中,后端直接返回数据给前端,无需视图渲染。

  • 可以写在方法上,也可以写在类上(此时表示该类所有方法的返回值都直接写入响应体)。

@RestController 注解

作用:相当于@Controller + @ResponseBody,表示该类是一个控制器,并且所有方法的返回值都直接写入响应体。

使用场景:适用于前后端分离的项目,后端直接返回JSON数据。

@RequestMapping 注解

作用:配置URL映射,将HTTP请求映射到具体的控制器方法。

使用场景:

  • 可以作用于类上(表示该类所有方法的URL前缀)或方法上(表示具体的URL路径)。
  • 支持多种HTTP方法(如GET、POST、PUT、DELETE等)。

@RequestParam 注解

作用:将请求参数绑定到控制器方法的参数上,适用于处理表单数据或URL查询参数。

使用场景:

  • 常用于GET请求或POST请求中处理表单数据。
  • 可以指定参数名称、是否必填、默认值等。

@Autowired 注解

作用:自动注入依赖,Spring容器会自动查找匹配的Bean并注入到字段、构造函数或方法中。

使用场景:用于注入服务层、数据访问层或其他组件。

@PathVariable 注解

作用:将URL路径中的占位符绑定到控制器方法的参数上。

使用场景:适用于RESTful风格的URL,如/user/{id}。

以下是一个综合使用多个注解的示例:

@RestController
@RequestMapping("/hello")
public class HelloController {

    @Autowired
    private UserService userService;

    @RequestMapping("/whoami/{name}/{sex}")
    public String hello(
            @PathVariable("name") String name,
            @PathVariable("sex") String sex,
            @RequestParam(value = "age", defaultValue = "18") int age) {
        return "Hello " + name + ", Sex: " + sex + ", Age: " + age;
    }
}

函数

在Java Web开发中,函数是代码的基本组成单元。不同层次的函数(如控制器函数、服务层函数、DAO层函数)有不同的职责和设计原则。

控制器函数

控制器函数是MVC架构中的入口,负责接收HTTP请求并返回响应。

职责:
1、接收请求参数(如URL参数、表单数据、JSON数据等)。
2、调用服务层处理业务逻辑。
3、返回响应(如视图名称、JSON数据等)。

示例:

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable("id") int id) {
        User user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }

    @PostMapping("/create")
    public ResponseEntity<String> createUser(@RequestBody User user) {
        userService.createUser(user);
        return ResponseEntity.ok("User created successfully");
    }
}

设计原则:
1、每个控制器函数只处理一个具体的请求。
2、控制器函数应尽量简洁,复杂的业务逻辑应交给服务层处理。
3、对请求参数进行校验,确保数据的合法性。

服务层函数

服务层函数是业务逻辑的核心,负责处理具体的业务规则和流程。

职责:
1、实现业务逻辑(如数据验证、计算、流程控制等)。
2、调用DAO层与数据库交互。
3、处理事务管理(如使用@Transactional注解)。

示例:

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional
    public User getUserById(int id) {
        return userRepository.findById(id)
                .orElseThrow(() -> new UserNotFoundException("User not found"));
    }

    @Override
    @Transactional
    public void createUser(User user) {
        if (userRepository.existsByEmail(user.getEmail())) {
            throw new DuplicateUserException("Email already exists");
        }
        userRepository.save(user);
    }
}

设计原则:
1、每个服务函数应专注于一个具体的业务功能。
2、服务函数应尽量减少与其他模块的依赖。
3、涉及数据库操作的函数应使用事务管理,确保数据一致性。

DAO层函数

DAO(Data Access Object)层函数负责与数据库交互,执行增删改查等操作。

职责:

  • 执行数据库操作(如查询、插入、更新、删除)。

  • 封装数据库访问细节,提供简单的接口供服务层调用。

示例:

// 使用 @Repository 注解标记该接口为 Spring 的数据访问层(DAO)组件。
// Spring 会自动扫描并管理该接口的实现。
@Repository
// UserRepository 接口继承自 JpaRepository,提供了基本的 CRUD 操作。
// JpaRepository<User, Integer> 表示该仓库操作的是 User 实体类,且主键类型为 Integer。
public interface UserRepository extends JpaRepository<User, Integer> {

    // 根据用户 ID 查询用户信息。
    // 返回一个 Optional<User> 对象,避免空指针异常。
    Optional<User> findById(int id);

    // 检查数据库中是否存在指定邮箱的用户。
    // 返回一个布尔值,true 表示存在,false 表示不存在。
    boolean existsByEmail(String email);

    // 使用自定义的 JPQL 查询语句,查询年龄大于指定值的用户列表。
    // @Query 注解用于定义 JPQL 查询。
    // :age 是命名参数,通过 @Param 注解与方法参数绑定。
    @Query("SELECT u FROM User u WHERE u.age > :age")
    List<User> findUsersOlderThan(@Param("age") int age);
}

设计原则:
1、每个DAO函数只负责一个具体的数据库操作。
2、DAO函数应尽量简洁,避免复杂的业务逻辑。
3、注意SQL语句的性能优化,避免全表扫描等低效操作。

数据常见处理方法

不可信数据是指来自外部、可能包含恶意内容的输入,例如用户提交的表单数据、URL参数以及第三方 API 返回的数据。因此,需要谨慎编写针对数据的处理方法。

常见场景:
1、用户输入的表单数据
2、URL参数
3、文件上传
4、请求体数据

常见的获取数据方法:

方法说明
getParameter获取请求参数值
getParameterNames获取所有参数名
getParameterValues获取某个参数的所有值
getParameterMap获取参数的键值对映射
getQueryString获取 URL 查询字符串
getHeader获取指定的 HTTP 请求头
getHeaderNames获取所有请求头名称
getRequestURI获取请求的 URL
getCookies获取 Cookie 信息
getRequestedSessionId获取 Session ID
getInputStream以流的方式读取请求体数据
getReader以字符流的方式读取请求内容
getMethod获取请求方法(如 GET、POST)
getProtocol获取请求协议
getServerName获取服务器名称
getRemoteUser获取当前缓存的用户
getUserPrincipal获取用户身份信息

在处理不可信数据时,必须进行严格的校验和过滤,以防止安全漏洞(如 SQL 注入、XSS 攻击等):
1、对输入数据进行严格校验(如正则匹配、白名单限制)。
2、采用安全的解析方式,避免直接拼接用户输入内容。
3、使用安全编码(如 HTML 转义)来防范 XSS 攻击。

不可信文件访问及安全防范

在处理不可信文件时,需要谨慎编写针对文件的处理方法,确保文件路径和内容的安全性,以防范路径遍历攻击恶意文件上传等风险。

常见文件操作方法:

方法说明
java.io.FileInputStream读取文件内容(字节流)
java.io.FileOutputStream写入文件内容(字节流)
java.io.FileReader读取文件内容(字符流)
java.io.FileWriter写入文件内容(字符流)

安全处理原则:
1、进行路径校验,确保访问的文件路径在允许的范围内,避免目录遍历漏洞(如 ../../../etc/passwd)。
2、严格校验文件扩展名、MIME 类型及文件内容,防止上传恶意脚本文件(如 .jsp.php)。
3、在处理上传文件时,使用临时目录存储并验证后再移动,降低风险。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋说

感谢打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值