在网约车项目中,抢单功能是非常关键的一部分,它决定了司机能否及时响应乘客的订单,提高整个平台的运营效率。本文将详细介绍如何使用Java来实现网约车项目的抢单功能,并提供一个完整的代码示例,以便读者能够直接运行和参考。

一、项目背景与需求分析

1.项目背景

随着移动互联网的快速发展,网约车已成为人们日常出行的重要选择。一个高效的网约车平台,除了需要提供良好的用户注册、登录、下单等功能外,还需要确保司机能够迅速响应乘客的订单,即实现抢单功能。

2.需求分析

  • 乘客端:乘客可以发布订单,并查看订单状态(如待抢单、已抢单、已完成等)。
  • 司机端:司机可以查看当前附近的订单,并选择抢单。抢单成功后,司机需前往乘客指定的地点接乘客。
  • 后台管理:管理员可以查看所有订单和司机的状态,进行必要的调度和管理。

二、技术选型与架构设计

1.技术选型

  • 后端:Java(Spring Boot框架)
  • 数据库:MySQL
  • 缓存:Redis(用于实现分布式锁,确保抢单操作的原子性)
  • 前端:Vue.js(乘客端和司机端界面)
  • 通信协议:HTTP/HTTPS(使用RESTful API进行前后端通信)

2.架构设计

  • 乘客端:负责接收乘客的输入,将订单信息发送到后端服务器。
  • 司机端:显示附近的订单列表,提供抢单功能,将抢单请求发送到后端服务器。
  • 后端服务器:处理乘客和司机的请求,存储订单信息,管理司机状态,实现抢单逻辑。
  • 数据库:存储乘客、司机、订单等信息。
  • Redis:用于实现分布式锁,确保在并发情况下只有一个司机能够成功抢单。

三、数据库设计

1.乘客表(passenger)

字段名 类型 备注
id INT 主键,自增
name VARCHAR 乘客姓名
phone VARCHAR 乘客手机号
password VARCHAR 乘客密码
address VARCHAR 乘客地址

2.司机表(driver)

字段名 类型 备注
id INT 主键,自增
name VARCHAR 司机姓名
phone VARCHAR 司机手机号
password VARCHAR 司机密码
status INT 司机状态(0:空闲,1:已抢单)

3.订单表(order)

字段名 类型 备注
id INT 主键,自增
passenger_id INT 乘客ID
start_address VARCHAR 起始地址
end_address VARCHAR 目的地址
status INT 订单状态(0:待抢单,1:已抢单,2:已完成)
driver_id INT 抢单司机ID(为空表示待抢单)

四、后端实现

1.创建Spring Boot项目

使用Spring Initializr创建一个Spring Boot项目,选择所需的依赖(如Spring Web、Spring Data JPA、MySQL Driver等)。

2.配置数据库连接

application.properties文件中配置数据库连接信息:

spring.datasource.url=jdbc:mysql://localhost:3306/ride_sharing?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

3.创建实体类

// Passenger.java
@Entity
public class Passenger {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String phone;
private String password;
private String address; // Getters and Setters
} // Driver.java
@Entity
public class Driver {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String phone;
private String password;
private Integer status = 0; // 0: 空闲, 1: 已抢单 // Getters and Setters
} // Order.java
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long passengerId;
private String startAddress;
private String endAddress;
private Integer status = 0; // 0: 待抢单, 1: 已抢单, 2: 已完成
private Long driverId; // 为空表示待抢单 // Getters and Setters
}

4.创建Repository接口

// PassengerRepository.java
public interface PassengerRepository extends JpaRepository<Passenger, Long> {} // DriverRepository.java
public interface DriverRepository extends JpaRepository<Driver, Long> {} // OrderRepository.java
public interface OrderRepository extends JpaRepository<Order, Long> {}

5.实现抢单逻辑

为了实现抢单功能的原子性,我们需要使用Redis来实现分布式锁。以下是实现抢单逻辑的Service类:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit; @Service
public class OrderService { @Autowired
private OrderRepository orderRepository; @Autowired
private DriverRepository driverRepository; @Autowired
private StringRedisTemplate redisTemplate; private static final String LOCK_KEY = "order_lock:";
private static final int LOCK_EXPIRE_TIME = 10; // 锁过期时间(秒) @Transactional
public String grabOrder(Long driverId, Long orderId) {
// 使用Redis实现分布式锁
String lockKey = LOCK_KEY + orderId;
Boolean lock = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
if (lock == null || !lock) {
return "抢单失败,订单已被其他司机抢单";
} try {
// 查询订单信息
Optional<Order> optionalOrder = orderRepository.findById(orderId);
if (!optionalOrder.isPresent()) {
return "订单不存在";
} Order order = optionalOrder.get();
if (order.getStatus() != 0) {
return "抢单失败,订单状态异常";
} // 更新订单状态和司机ID
order.setStatus(1);
order.setDriverId(driverId);
orderRepository.save(order); // 更新司机状态
Optional<Driver> optionalDriver = driverRepository.findById(driverId);
if (optionalDriver.isPresent()) {
Driver driver = optionalDriver.get();
driver.setStatus(1);
driverRepository.save(driver);
} return "抢单成功";
} finally {
// 释放锁
redisTemplate.delete(lockKey);
}
} public List<Order> getNearbyOrders(Double latitude, Double longitude) {
// 根据经纬度查询附近的订单(这里简化处理,只返回所有待抢单订单)
return orderRepository.findAllByStatus(0);
}
}

6.创建Controller类

OrderController类的getNearbyOrders方法补充完整,并确保其逻辑与抢单功能相匹配。此外,为了更贴近实际需求,getNearbyOrders方法应当能够基于司机的位置(纬度和经度)来筛选附近的订单,尽管在实际应用中这通常涉及更复杂的地理空间查询。但在此示例中,为了简化,我们将仅返回所有待抢单的订单,并在注释中指出应如何实现更复杂的逻辑。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import java.util.List; @RestController
@RequestMapping("/api/orders")
public class OrderController { @Autowired
private OrderService orderService; @PostMapping("/grab")
public String grabOrder(@RequestParam Long driverId, @RequestParam Long orderId) {
return orderService.grabOrder(driverId, orderId);
} @GetMapping("/nearby")
public List<Order> getNearbyOrders(@RequestParam Double latitude, @RequestParam Double longitude) {
// 在实际应用中,这里应该包含基于地理位置的查询逻辑,
// 例如使用数据库中的地理空间索引或第三方地理空间搜索服务。
// 但为了简化示例,我们仅返回所有待抢单的订单。
// 注意:在生产环境中,直接返回所有待抢单订单可能不是最佳实践,
// 因为这可能会暴露过多信息给司机,并增加后端服务器的负载。 // 假设我们有一个方法来根据司机的位置计算附近订单的半径(例如5公里)
// 但由于我们简化了地理空间查询,所以这里不实现这个方法。 // 返回一个筛选后的订单列表,仅包含状态为“待抢单”的订单
// 在实际应用中,这里应该有一个更复杂的查询,基于司机的位置和订单的位置
return orderService.getNearbyOrders(0); // 0 表示待抢单状态 // 注意:上面的调用中我们传递了状态码0作为参数,但在OrderService的getNearbyOrders方法中
// 我们实际上并没有使用这个参数来进行筛选(因为我们的示例简化了地理空间查询)。
// 在实际的OrderService实现中,你应该修改这个方法以接受状态码作为参数,并据此来筛选订单。
// 例如:return orderRepository.findAllByStatusAndWithinRadius(0, latitude, longitude, radius);
// 这里的withinRadius方法是一个假设的方法,用于执行地理空间查询。
}
}

OrderController类的getNearbyOrders方法补充完整,并确保其逻辑与抢单功能相匹配。此外,为了更贴近实际需求,getNearbyOrders方法应当能够基于司机的位置(纬度和经度)来筛选附近的订单,尽管在实际应用中这通常涉及更复杂的地理空间查询。但在此示例中,为了简化,我们将仅返回所有待抢单的订单,并在注释中指出应如何实现更复杂的逻辑。

7. 配置安全性(如Spring Security)

为了保障系统的安全性,通常需要配置用户认证和授权。

配置类

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; @Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/orders/grab/**").authenticated() // 需要认证才能访问抢单接口
.anyRequest().permitAll()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll();
} @Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

8. 创建Service类

Service类用于处理业务逻辑,比如验证司机资格、更新订单状态等。

OrderService.java:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @Service
public class OrderService { @Autowired
private OrderRepository orderRepository; @Autowired
private DriverRepository driverRepository; @Transactional
public boolean grabOrder(Long orderId, Long driverId) {
Optional<Order> optionalOrder = orderRepository.findById(orderId);
if (!optionalOrder.isPresent() || optionalOrder.get().getStatus() != OrderStatus.AVAILABLE) {
return false;
} Optional<Driver> optionalDriver = driverRepository.findById(driverId);
if (!optionalDriver.isPresent()) {
return false;
} Order order = optionalOrder.get();
order.setDriver(optionalDriver.get());
order.setStatus(OrderStatus.GRABBED);
orderRepository.save(order);
return true;
}
}

9. 配置消息队列(如RabbitMQ或Kafka)

对于抢单功能,使用消息队列可以提高系统的并发处理能力和响应速度。

RabbitMQ配置类:

import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class RabbitMQConfig { public static final String QUEUE_NAME = "orderQueue"; @Bean
Queue queue() {
return new Queue(QUEUE_NAME, true);
} @Bean
SimpleMessageListenerContainer container(ConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(QUEUE_NAME);
container.setMessageListener(listenerAdapter);
return container;
} @Bean
MessageListenerAdapter listenerAdapter(OrderService orderService) {
return new MessageListenerAdapter(orderService, "processOrder");
} @Bean
RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
return new RabbitTemplate(connectionFactory);
}
}

OrderService中添加处理消息的方法:

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; @Service
public class OrderService { // 之前的代码... @Autowired
private RabbitTemplate rabbitTemplate; public void publishOrder(Order order) {
rabbitTemplate.convertAndSend(RabbitMQConfig.QUEUE_NAME, order);
} public void processOrder(Order order) {
// 逻辑处理,比如将订单状态更新为已分配等
// 这里可以调用grabOrder方法或其他逻辑
}
}

10. 单元测试

编写单元测试来验证你的抢单逻辑。

OrderServiceTest.java:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class)
public class OrderServiceTest { @Mock
private OrderRepository orderRepository; @Mock
private DriverRepository driverRepository; @InjectMocks
private OrderService orderService; @Test
public void testGrabOrderSuccess() {
Order order = new Order();
order.setId(1L);
order.setStatus(OrderStatus.AVAILABLE); Driver driver = new Driver();
driver.setId(1L); when(orderRepository.findById(1L)).thenReturn(Optional.of(order));
when(driverRepository.findById(1L)).thenReturn(Optional.of(driver)); boolean result = orderService.grabOrder(1L, 1L); assertTrue(result);
verify(orderRepository, times(1)).save(any(Order.class));
} @Test
public void testGrabOrderOrderNotFound() {
when(orderRepository.findById(1L)).thenReturn(Optional.empty()); boolean result = orderService.grabOrder(1L, 1L); assertFalse(result);
verify(orderRepository, never()).save(any(Order.class));
} // 更多测试...
}

11. 日志记录

使用日志记录库(如SLF4J和Logback)来记录关键操作。

在application.properties中配置Logback:

properties复制代码

logging.level.com.example.ridesharing=DEBUG

在Service类中记录日志:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory; @Service
public class OrderService { private static final Logger logger = LoggerFactory.getLogger(OrderService.class); // 之前的代码... @Transactional
public boolean grabOrder(Long orderId, Long driverId) {
logger.debug("Attempting to grab order {} by driver {}", orderId, driverId); Optional<Order> optionalOrder = orderRepository.findById(orderId);
if (!optionalOrder.isPresent() || optionalOrder.get().getStatus() != OrderStatus.AVAILABLE) {
logger.debug("Order {} is not available or does not exist", orderId);
return false;
} Optional<Driver> optionalDriver = driverRepository.findById(driverId);
if (!optionalDriver.isPresent()) {
logger.debug("Driver {} does not exist", driverId);
return false;
} Order order = optionalOrder.get();
order.setDriver(optionalDriver.get());
order.setStatus(OrderStatus.GRABBED);
orderRepository.save(order); logger.debug("Order {} successfully grabbed by driver {}", orderId, driverId);
return true;
}
}

12. 部署和运维

最后,考虑如何部署和运维你的应用,包括使用Docker进行容器化、配置CI/CD管道等。

这些步骤和代码示例提供了一个完整的框架,用于实现一个包含抢单功能的网约车项目。当然,根据具体需求,你可能需要调整或添加更多的功能。

五、前端实现

在Java网约车项目实战中实现抢单功能的前端部分,通常可以使用前端框架如React、Vue.js或Angular来构建用户界面。为了简单起见,这里我们使用React和Redux来实现一个基本的前端应用,该应用允许司机查看订单并抢单。

1.项目结构

假设项目结构如下:

my-ridesharing-app/
├── public/
│ ├── index.html
│ └── ...
├── src/
│ ├── actions/
│ │ └── orderActions.js
│ ├── components/
│ │ ├── OrderList.js
│ │ ├── OrderItem.js
│ │ └── App.js
│ ├── reducers/
│ │ └── orderReducer.js
│ ├── store/
│ │ └── index.js
│ ├── index.js
│ └── ...
├── package.json
└── ...

2.安装依赖

首先,确保你已经安装了Node.js和npm,然后在项目根目录下运行以下命令来初始化React项目并安装必要的依赖:

npx create-react-app my-ridesharing-app
cd my-ridesharing-app
npm install redux react-redux redux-thunk axios

3.实现前端代码

(1) src/store/index.js - 配置Redux Store

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers'; const store = createStore(rootReducer, applyMiddleware(thunk)); export default store;

(2)src/reducers/orderReducer.js - 定义Reducer

const initialState = {
orders: [],
loading: false,
error: null,
}; const fetchOrdersSuccess = (state, action) => ({
...state,
orders: action.payload,
loading: false,
error: null,
}); const fetchOrdersFailure = (state, action) => ({
...state,
loading: false,
error: action.payload,
}); const grabOrderSuccess = (state, action) => {
const updatedOrders = state.orders.map(order =>
order.id === action.payload.id ? { ...order, grabbed: true } : order
);
return {
...state,
orders: updatedOrders,
};
}; const orderReducer = (state = initialState, action) => {
switch (action.type) {
case 'FETCH_ORDERS_REQUEST':
return {
...state,
loading: true,
};
case 'FETCH_ORDERS_SUCCESS':
return fetchOrdersSuccess(state, action);
case 'FETCH_ORDERS_FAILURE':
return fetchOrdersFailure(state, action);
case 'GRAB_ORDER_SUCCESS':
return grabOrderSuccess(state, action);
default:
return state;
}
}; export default orderReducer;

(3)src/actions/orderActions.js - 定义Action Creators

import axios from 'axios';

export const fetchOrders = () => async dispatch => {
dispatch({ type: 'FETCH_ORDERS_REQUEST' });
try {
const response = await axios.get('/api/orders'); // 假设后端API地址
dispatch({ type: 'FETCH_ORDERS_SUCCESS', payload: response.data });
} catch (error) {
dispatch({ type: 'FETCH_ORDERS_FAILURE', payload: error.message });
}
}; export const grabOrder = orderId => async dispatch => {
try {
const response = await axios.post(`/api/orders/${orderId}/grab`); // 假设后端API地址
dispatch({ type: 'GRAB_ORDER_SUCCESS', payload: response.data });
} catch (error) {
console.error('Grab order failed:', error.message);
}
};

(4)src/components/OrderItem.js - 订单项组件

import React from 'react';
import { useDispatch } from 'react-redux';
import { grabOrder } from '../actions/orderActions'; const OrderItem = ({ order }) => {
const dispatch = useDispatch(); const handleGrab = () => {
dispatch(grabOrder(order.id));
}; return (
<div>
<h3>{order.passengerName}</h3>
<p>Pickup: {order.pickupLocation}</p>
<p>Dropoff: {order.dropoffLocation}</p>
<button onClick={handleGrab} disabled={order.grabbed}>
{order.grabbed ? 'Grabbed' : 'Grab Order'}
</button>
</div>
);
}; export default OrderItem;

(5) src/components/OrderList.js - 订单列表组件

import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchOrders } from '../actions/orderActions';
import OrderItem from './OrderItem'; const OrderList = () => {
const dispatch = useDispatch();
const { orders, loading, error } = useSelector(state => state.orders); useEffect(() => {
dispatch(fetchOrders());
}, [dispatch]); if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>; return (
<div>
<h2>Orders</h2>
{orders.map(order => (
<OrderItem key={order.id} order={order} />
))}
</div>
);
}; export default OrderList;

(6)src/components/App.js - 主应用组件

import React from 'react';
import OrderList from './OrderList';
import { Provider } from 'react-redux';
import store from '../store'; const App = () => (
<Provider store={store}>
<div className="App">
<h1>Ridesharing App</h1>
<OrderList />
</div>
</Provider>
); export default App;

(7) src/index.js - 入口文件

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import reportWebVitals from './reportWebVitals'; ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
); reportWebVitals();

4.后端API

注意,上面的代码假设后端API存在,并且提供了以下两个端点:

(1)GET /api/orders - 获取所有未被抓取的订单。

(2)POST /api/orders/:orderId/grab - 抓取指定订单。

你需要在后端实现这些API端点,并确保它们能够返回正确的数据。

5.运行应用

在项目根目录下运行以下命令来启动React应用:

bash复制代码

npm start

这将启动开发服务器,并在浏览器中打开你的应用。你应该能看到一个订单列表,并且可以点击“Grab Order”按钮来抓取订单。

以上就是一个简单的React前端实现,用于在网约车项目中实现抢单功能。你可以根据实际需求进一步扩展和优化这个应用。

在Java网约车项目实战中,实现抢单功能是一个核心且复杂的部分。除了你提到的几个主要部分(项目背景与需求分析、技术选型与架构设计、数据库设计、后端实现、前端实现)外,通常还需要包含以下关键内容,以确保项目的完整性和健壮性:

六、系统测试

  1. 单元测试:针对后端实现的各个模块,编写单元测试代码,确保每个模块的功能正常。
  2. 集成测试:将各个模块集成在一起后,进行整体测试,确保系统整体功能正常。
  3. 压力测试:模拟高并发场景,测试系统在抢单等高并发操作下的性能和稳定性。
  4. 安全测试:测试系统的安全性,确保用户数据和订单信息不会被泄露或篡改。

七、性能优化

  1. 代码优化:对后端代码进行优化,提高代码的执行效率和可读性。
  2. 数据库优化:对数据库进行查询优化、索引优化等,提高数据库的查询速度和响应能力。
  3. 缓存策略:使用Redis等缓存技术,减少对数据库的访问压力,提高系统的响应速度。

八、部署与运维

  1. 系统部署:将系统部署到服务器或云平台上,确保系统能够正常运行。
  2. 运维监控:对系统进行监控,及时发现并处理系统异常和故障。
  3. 日志管理:对系统日志进行管理,确保日志的完整性和可读性,方便后续的问题排查和性能分析。

九、文档编写

  1. 技术文档:编写详细的技术文档,包括系统的架构设计、数据库设计、接口文档等,方便后续的开发和维护。
  2. 用户手册:编写用户手册,指导用户如何使用系统,包括系统的功能介绍、操作流程等。

十、项目总结与反思

  1. 项目总结:对整个项目进行总结,包括项目的完成情况、遇到的问题及解决方案等。
  2. 经验反思:对项目的经验进行反思,总结在项目开发过程中的得失,为后续的项目开发提供参考。

综上所述,一个完整的Java网约车项目实战,除了实现抢单功能的核心部分外,还需要考虑系统测试、性能优化、部署与运维、文档编写以及项目总结与反思等关键内容。这些内容对于确保项目的成功交付和后续维护具有重要意义。

Java网约车项目实战:实现抢单功能详解的更多相关文章

  1. SpringCloud微服务项目实战 - API网关Gateway详解实现

    前面讲过zuul的网关实现,那为什么今天又要讲Spring Cloud Gateway呢?原因很简单.就是Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用 ...

  2. java并发系列(三)-----ReentrantLock(重入锁)功能详解和应用演示

    1. ReentrantLock简介 jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock.虽然在性能上ReentrantLock和synchronize ...

  3. 出租车Jt/T 905协议与部标1078协议融合的网约车视频监控平台

    出租车jt/t 905协议,是jt/t 808协议的一个变种,设计者将部标808协议拿过来,并不是单纯的增加网约车相关的指令集,而且对原有的指令如定位0×0200指令也进行了修改,经过一通剧烈的修改, ...

  4. XSS钓鱼某网约车后台一探究竟,乘客隐私暴露引发思考

    i春秋作家:onls辜釉 最近的某顺风车命案,把网约车平台推上了风口浪尖,也将隐私信息管理.审查的讨论面进一步扩大.这让我不禁联想起自己今年春节的遭遇,当时公司放假准备回家过年,我妈给我推荐了一个在我 ...

  5. Java工程师 基础+实战 完整路线图(详解版)

    Java工程师 基础+实战 完整路线图(详解版)   Java 基础 Java 是一门纯粹的面向对象的编程语言,所以除了基础语法之外,必须得弄懂它的 oop 特性:封装.继承.多态.此外还有泛型.反射 ...

  6. 用maven来创建scala和java项目代码环境(图文详解)(Intellij IDEA(Ultimate版本)、Intellij IDEA(Community版本)和Scala IDEA for Eclipse皆适用)(博主推荐)

    不多说,直接上干货! 为什么要写这篇博客? 首先,对于spark项目,强烈建议搭建,用Intellij IDEA(Ultimate版本),如果你还有另所爱好尝试Scala IDEA for Eclip ...

  7. Scala IDEA for Eclipse里用maven来创建scala和java项目代码环境(图文详解)

    这篇博客 是在Scala IDEA for Eclipse里手动创建scala代码编写环境. Scala IDE for Eclipse的下载.安装和WordCount的初步使用(本地模式和集群模式) ...

  8. Java生产环境下性能监控与调优详解视频教程 百度云 网盘

    集数合计:9章Java视频教程详情描述:A0193<Java生产环境下性能监控与调优详解视频教程>软件开发只是第一步,上线后的性能监控与调优才是更为重要的一步本课程将为你讲解如何在生产环境 ...

  9. IdentityServer4实战 - JWT Token Issuer 详解

    原文:IdentityServer4实战 - JWT Token Issuer 详解 一.前言 本文为系列补坑之作,拖了许久决定先把坑填完. 下文演示所用代码采用的 IdentityServer4 版 ...

  10. 《手把手教你》系列技巧篇(二十七)-java+ selenium自动化测试- quit和close的区别(详解教程)

    1.简介 尽管有的小伙伴或者童鞋们觉得很简单,不就是关闭退出浏览器,但是宏哥还是把两个方法的区别说一下,不然遇到坑后根本不会想到是这里的问题. 2.源码 本文介绍webdriver中关于浏览器退出操作 ...

随机推荐

  1. 妙用编辑器:把EverEdit变成计算器

    妙用编辑器:把EverEdit变成计算器 应用场景 日常工作过程中,会存在需要计算一些数据的场景,调用系统的计算器当然可以完成这项工作,但是需要来回切换,且系统自带的计算器没有表达式计算功能,真是不方 ...

  2. KubeSphere 核心架构浅析

    作者简介:万宏明,KubeSphere 核心贡献者,专注于云原生安全领域. KubeSphere 是在 Kubernetes 之上构建的面向云原生应用的容器混合云管理系统.支持多云与多集群管理,提供全 ...

  3. 七、Spring Boot集成Spring Security之前后分离认证最佳实现

    二.自定义用户名密码认证过滤器RestfulUsernamePasswordAuthenticationFilter 1.注册过滤器方式 使用httpSecurity.addFilter/addFil ...

  4. 利用AI运动识别插件,可以实现那些应用场景?

    「Ai运动识别」小程序插件已经推出一年有余,迭代了近十几个版本,收获了各类应用场景的众多用户,今天我们就带您深度解析一下插件的各类可应用场景,帮助已集成开发者进行一步拓宽应用场景,帮助有需求的开发者快 ...

  5. 一款绘制3D架构图的在线神器:iCraft Editor

    在软件开发的世界里,架构图是系统设计的蓝图,它们不仅帮助团队理解系统的整体结构,还能提升沟通效率,确保项目的顺利推进.然而,绘制一张清晰.直观的架构图,往往需要大量时间和专业工具.面对繁琐的操作和复杂 ...

  6. AI翻唱神器,一键用你喜欢的歌手翻唱他人的曲目(附下载链接)

    最近,"AI孙燕姿"翻唱众多明星的歌曲在各大网络平台上走红,其作品不仅累积上千万的播放量,在科技圈和音乐圈也都引发了热议,歌手孙燕姿在社交平台发文回应称:人类无法超越AI技术已指日 ...

  7. cornerstone中raft_server_req_handlers源码解析

    1.概述 之前说过raft_server是cornerstone的核心,其中充满了很多req的发送,那么follower收到leader的req会怎么处理呢? 本文就是来解析cornerstone中处 ...

  8. 怎么理解Condition

    原文出处: liuinsect 感谢文章作者@Jd刘锟洋 的投稿.如果其他朋友也希望自己的 Java 和 Android 技术文章发表在 ImportNew,可以微博私信联系@ImportNew,或者 ...

  9. Django之form表单的数据验证

    1.先导入forms模块 from django import forms 2.创建模板的类 class loginform(forms.Form): # 2.模板中的元素 name = forms. ...

  10. MySQL8.0之特性

    MySQL 8.0 正式版 8.0.11 已发布,官方表示 MySQL 8 要比 MySQL 5.7 快 2 倍,还带来了大量的改进和更快的性能.下面我们将简要介绍下 MySQL 8.0 中值得关注的 ...