如何修改端口

要修改Web服务器端口,只需在 application.properties 文件中添加以下配置:

spring.application.name=demo
server.port=8081

常用端口配置示例

# 修改为8081端口
server.port=8081

# 修改为9000端口
server.port=9000

# 修改为3000端口(常用于前端开发)
server.port=3000

# 使用随机端口(测试时有用)
server.port=0

其他相关配置

还可以配置其他服务器相关属性:

# 端口配置
server.port=8081

# 上下文路径(访问路径前缀)
server.servlet.context-path=/api

# 服务器地址(默认为所有接口)
server.address=localhost

# 会话超时时间
server.servlet.session.timeout=30m

1. @RequestBody 的作用

@RequestBody 注解用于将HTTP请求体中的JSON数据自动映射到Java对象。Spring Boot会自动处理这个转换过程。

2. 自动映射机制

Spring Boot使用Jackson库(默认的JSON处理器)来完成JSON到Java对象的转换:

  1. 序列化:Java对象 → JSON(响应时)
  2. 反序列化:JSON → Java对象(请求时,@RequestBody的作用)

3. 如何编写接收类(DTO/Entity)

基本要求:

  • 使用类(Class)
  • 提供无参构造函数
  • 提供getter/setter方法(或使用Lombok)
  • 字段名要与JSON中的key对应

示例代码:

// 方式1:传统写法
public class User {
    private String name;
    private Integer age;
    private String email;
    
    // 无参构造函数(必需)
    public User() {}
    
    // 有参构造函数(可选)
    public User(String name, Integer age, String email) {
        this.name = name;
        this.age = age;
        this.email = email;
    }
    
    // Getter和Setter方法
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
}

// 方式2:使用Lombok(推荐)
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;

@Data  // 自动生成getter/setter/toString/equals/hashCode
@NoArgsConstructor  // 无参构造函数
@AllArgsConstructor // 全参构造函数
public class User {
    private String name;
    private Integer age;
    private String email;
}

tip:
如果想要使用Lombok,需要在pom.xml中写入依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

4. Controller中的使用

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        // Spring自动将JSON转换为User对象
        System.out.println("接收到用户:" + user.getName());
        
        // 处理业务逻辑
        User savedUser = userService.save(user);
        
        return ResponseEntity.ok(savedUser);
    }
    
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(
            @PathVariable Long id, 
            @RequestBody User user) {
        User updatedUser = userService.update(id, user);
        return ResponseEntity.ok(updatedUser);
    }
}

5. JSON映射示例

前端发送的JSON:

{
    "name": "张三",
    "age": 25,
    "email": "[email protected]"
}

自动映射到User对象:

User user = new User();
user.setName("张三");
user.setAge(25);
user.setEmail("[email protected]");

6. 高级特性

字段验证:

import javax.validation.constraints.*;

public class UserCreateDTO {
    @NotBlank(message = "姓名不能为空")
    @Size(min = 2, max = 50, message = "姓名长度必须在2-50之间")
    private String name;
    
    @NotNull(message = "年龄不能为空")
    @Min(value = 0, message = "年龄不能为负数")
    @Max(value = 150, message = "年龄不能超过150")
    private Integer age;
    
    @Email(message = "邮箱格式不正确")
    private String email;
}

// Controller中启用验证
@PostMapping
public ResponseEntity<User> createUser(@Valid @RequestBody UserCreateDTO dto) {
    // 如果验证失败,Spring会自动返回400错误
    return ResponseEntity.ok(userService.create(dto));
}

JSON字段映射:

import com.fasterxml.jackson.annotation.JsonProperty;

public class UserDTO {
    @JsonProperty("user_name")  // JSON中的字段名
    private String name;        // Java中的字段名
    
    @JsonProperty("user_age")
    private Integer age;
}

1. 基本概念

@RequestMapping 是Spring MVC中最基础的请求映射注解,可以处理所有HTTP方法(GET、POST、PUT、DELETE等)。

@GetMapping 是Spring 4.3引入的组合注解,专门用于处理HTTP GET请求,本质上是 @RequestMapping(method = RequestMethod.GET) 的简化写法。

2. 主要区别

语法简洁性

// 使用 @RequestMapping
@RequestMapping(value = "/users", method = RequestMethod.GET)
public List<User> getUsers() {
    return userService.getAllUsers();
}

// 使用 @GetMapping(更简洁)
@GetMapping("/users")
public List<User> getUsers() {
    return userService.getAllUsers();
}

HTTP方法支持

  • @RequestMapping: 支持所有HTTP方法,需要通过 method 属性指定
  • @GetMapping: 只支持GET请求,无需指定method属性

类型安全

  • @RequestMapping: 如果忘记指定method,默认支持所有HTTP方法
  • @GetMapping: 类型安全,明确表示只处理GET请求

3. 其他相似的组合注解

Spring还提供了其他HTTP方法的组合注解:

  • @PostMapping = @RequestMapping(method = RequestMethod.POST)
  • @PutMapping = @RequestMapping(method = RequestMethod.PUT)
  • @DeleteMapping = @RequestMapping(method = RequestMethod.DELETE)
  • @PatchMapping = @RequestMapping(method = RequestMethod.PATCH)

4. 使用建议

  1. 优先使用具体的组合注解:如@GetMapping、@PostMapping等,代码更清晰
  2. @RequestMapping适用场景

    • 类级别的基础路径映射
    • 需要处理多种HTTP方法的场景
    • 需要复杂配置的场景

5. 实际示例

@RestController
@RequestMapping("/api/users")  // 类级别基础路径
public class UserController {
    
    @GetMapping  // 处理 GET /api/users
    public List<User> getAllUsers() {
        return userService.findAll();
    }
    
    @GetMapping("/{id}")  // 处理 GET /api/users/{id}
    public User getUserById(@PathVariable Long id) {
        return userService.findById(id);
    }
    
    @PostMapping  // 处理 POST /api/users
    public User createUser(@RequestBody User user) {
        return userService.save(user);
    }
    
    // 如果需要同时处理多种方法
    @RequestMapping(value = "/batch", method = {RequestMethod.POST, RequestMethod.PUT})
    public ResponseEntity<String> batchOperation() {
        return ResponseEntity.ok("Batch operation completed");
    }
}

总结:@GetMapping是@RequestMapping的特化版本,专门用于GET请求,代码更简洁、类型更安全。在实际开发中,建议优先使用@GetMapping等具体的HTTP方法注解。

1. 作用域差异

普通CSS:

  • 全局作用域,所有样式都是全局的
  • 容易出现样式冲突和覆盖问题
/* styles.css */
.button {
    background-color: blue;
}
// 使用普通CSS
import './styles.css';
<button className="button">按钮</button>

CSS模块:

  • 局部作用域,样式只在当前组件内生效
  • 自动生成唯一的类名,避免冲突
/* Button.module.css */
.button {
    background-color: blue;
}
// 使用CSS模块
import styles from './Button.module.css';
<button className={styles.button}>按钮</button>

2. 类名生成机制

普通CSS:

  • 类名保持原样:.buttonbutton

CSS模块:

  • 自动生成哈希类名:.buttonButton_button__2x3kl
  • 确保每个组件的样式独立

3. 使用方式

普通CSS:

// 直接使用字符串
<div className="container header active">

CSS模块:

// 通过styles对象引用
<div className={styles.container}>
<div className={`${styles.header} ${styles.active}`}>

4. 优缺点对比

特性普通CSSCSS模块
学习成本中等
样式冲突容易发生几乎不会
代码维护困难(大项目)容易
性能一般更好(按需加载)
调试容易稍复杂(类名被哈希)

5. 适用场景

普通CSS适合:

  • 小型项目
  • 全局样式(重置样式、主题等)
  • 第三方库的样式覆盖

CSS模块适合:

  • 中大型项目
  • 组件化开发
  • 需要样式隔离的场景

useFocusEffect

useFocusEffect 是 React Navigation 提供的一个 Hook,专门用于处理页面获得焦点时的副作用。

基本用法:

import { useFocusEffect } from '@react-navigation/native';
import { useCallback } from 'react';

function MyScreen() {
  useFocusEffect(
    useCallback(() => {
      // 页面获得焦点时执行的代码
      console.log('页面获得焦点');
      
      // 返回清理函数(可选)
      return () => {
        console.log('页面失去焦点');
      };
    }, [])
  );
}

特点:

  • 每次页面获得焦点时都会执行
  • 支持清理函数,页面失去焦点时执行
  • 常用于数据刷新、订阅管理等场景

useCallback

useCallback 是 React 提供的性能优化 Hook,用于缓存函数引用。

基本语法:

const memoizedCallback = useCallback(
  () => {
    // 函数逻辑
  },
  [dependency1, dependency2] // 依赖数组
);

工作原理:

  • 只有当依赖数组中的值发生变化时,才会重新创建函数
  • 如果依赖数组为空 [],函数只会创建一次
  • 返回的是函数的缓存版本

使用场景:

  1. 防止子组件不必要的重渲染:

    function Parent() {
      const [count, setCount] = useState(0);
      
      // 没有 useCallback - 每次渲染都创建新函数
      const handleClick = () => {
     console.log('clicked');
      };
      
      // 使用 useCallback - 函数引用保持不变
      const memoizedHandleClick = useCallback(() => {
     console.log('clicked');
      }, []);
      
      return <Child onClick={memoizedHandleClick} />;
    }
  2. 与其他 Hook 配合使用:

    function MyComponent() {
      const [data, setData] = useState(null);
      
      const fetchData = useCallback(async () => {
     const result = await api.getData();
     setData(result);
      }, []); // 空依赖数组,函数只创建一次
      
      useEffect(() => {
     fetchData();
      }, [fetchData]); // fetchData 不会导致无限循环
    }

性能考虑

useCallback 的使用原则:

考虑使用:

  • 传递给子组件的函数
  • 作为其他 Hook 的依赖
  • 计算成本较高的函数

不考虑使用:

  • 简单的事件处理函数(如果没有传递给子组件)
  • 过度使用(useCallback 本身也有开销)

示例对比:

// 不需要 useCallback
function SimpleComponent() {
  const handleClick = () => {
    console.log('simple click');
  };
  
  return <button onClick={handleClick}>Click</button>;
}

// 需要 useCallback
function ComplexComponent({ children }) {
  const [count, setCount] = useState(0);
  
  const handleClick = useCallback(() => {
    // 复杂逻辑或传递给子组件
    setCount(prev => prev + 1);
  }, []);
  
  return (
    <div>
      {React.Children.map(children, child => 
        React.cloneElement(child, { onClick: handleClick })
      )}
    </div>
  );
}

总结

  • useFocusEffect:处理页面焦点变化的副作用,常用于数据刷新
  • useCallback:缓存函数引用,优化性能,防止不必要的重渲染
  • 结合使用:在导航场景中实现高效的数据刷新机制

这两个 Hook 在 React Native 应用中非常实用,特别是在处理页面导航和性能优化方面。