Spring Boot与Flutter登录请求遇404及连接拒绝问题求助
问题描述
用Spring Boot和Flutter开发移动端登录页面,Tomcat已正常启动并连接数据库,使用Pixel 4 API 31模拟器测试:
- 请求
http://192.168.2.6:8090/users/login时,点击登录按钮出现I/flutter ( 7730): Error: 404 - 改用
http://localhost:8090/users/login或http://127.0.0.1:8090/users/login时,出现连接拒绝错误
相关代码
App.java
@SpringBootApplication @EnableJpaRepositories("org.example.repository.*") @ComponentScan(basePackages = { "org.example.controller.*" }) @EntityScan("org.example.model.*") public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
UserController.java
@RestController @RequestMapping("/users") public class UserController { private final UserService userService; private UserMapper userMapper; // Inject UserMapper here @Autowired public UserController(UserService userService) { this.userService = userService; } @PostMapping("/register") // in mobile app doesn't need all users should be registered by corresponding gym public ResponseEntity<UserDTO> registerUser(@RequestBody UserDTO userDTO) { // Receive and validate userDTO from the client // Map userDTO to a User entity User userEntity = userService.registerUser(userDTO); // Map the resulting User entity to a UserDTO for the response UserDTO registeredUserDTO = UserMapper.mapToDTO(userEntity); return ResponseEntity.ok(registeredUserDTO); } @PostMapping("/login") public ResponseEntity<UserDTO> loginUser(@RequestBody UserDTO userDTO) throws AuthenticationException { // Validate the loginRequest, e.g., check for null values // Map userDTO to a User entity UserDTO loginUserDTO = userService.loginUser(userDTO); return ResponseEntity.ok(loginUserDTO); } }
application.properties
server.port=8090 server.tomcat.threads.max=200 server.connection-timeout=5s server.max-http-header-size=8KB server.tomcat.max-swallow-size=2MB server.tomcat.max-http-post-size=2MB spring.datasource.url=jdbc:mysql://localhost:3306/testdbgymapp?serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect spring.jpa.hibernate.ddl-auto=update
login_page.dart(Flutter应用)
import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; import 'home_page.dart'; class LoginDemo extends StatefulWidget { @override _LoginDemoState createState() => _LoginDemoState(); } class _LoginDemoState extends State<LoginDemo> { final TextEditingController usernameController = TextEditingController(); final TextEditingController passwordController = TextEditingController(); Future<void> loginUser() async { final response = await http.post( Uri.parse('http://192.168.2.6:8090/users/login'), headers: <String, String>{ 'Content-Type': 'application/json; charset=UTF-8', }, body: jsonEncode(<String, String>{ 'username': usernameController.text, 'password': passwordController.text, }), ); if (response.statusCode == 200) { // Successful login Navigator.push( context, MaterialPageRoute(builder: (_) => HomePage())); } else if (response.statusCode == 400) { // Invalid username or password print('Invalid username or password'); } else { // Handle other error cases print('Error: ${response.statusCode}'); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: Text("Login Page"), ), body: SingleChildScrollView( child: Column( children: <Widget>[ Padding( padding: const EdgeInsets.only(top: 60.0), child: Center( child: Container( width: 200, height: 150, decoration: BoxDecoration( color: Colors.red, borderRadius: BorderRadius.circular(50.0)), child: Image.asset('asset/images/gymApp-logo.png')), ), ), Padding( //padding: const EdgeInsets.only(left:15.0,right: 15.0,top:0,bottom: 0), padding: EdgeInsets.symmetric(horizontal: 15), child: TextField( decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Email', hintText: 'Enter valid email id as abc@gmail.com'), ), ), Padding( padding: const EdgeInsets.only( left: 15.0, right: 15.0, top: 15, bottom: 0), //padding: EdgeInsets.symmetric(horizontal: 15), child: TextField( obscureText: true, decoration: InputDecoration( border: OutlineInputBorder(), labelText: 'Password', hintText: 'Enter secure password'), ), ), TextButton( onPressed: (){ //TODO FORGOT PASSWORD SCREEN GOES HERE }, child: Text( 'Forgot Password', style: TextStyle(color: Colors.blue, fontSize: 15), ), ), Container( height: 50, width: 250, decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(20)), child: TextButton( onPressed: () { loginUser(); }, child: Text( 'Login', style: TextStyle(color: Colors.white, fontSize: 25), ), ), ), SizedBox( height: 130, ), Text('New User? Create Account') ], ), ), ); } }
Tomcat日志
2023-09-14T10:38:53.779+03:00 INFO 288 --- [ restartedMain] org.example.App : Starting App using Java 17.0.8 with PID 288 (C:\Users\giorg\IdeaProjects\gymApp\target\classes started by Λιτσα in C:\Users\giorg\IdeaProjects\gymApp)
2023-09-14T10:38:53.782+03:00 INFO 288 --- [ restartedMain] org.example.App : No active profile set, falling back to 1 default profile: "default"
2023-09-14T10:38:53.864+03:00 INFO 288 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2023-09-14T10:38:53.864+03:00 INFO 288 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2023-09-14T10:38:55.143+03:00 INFO 288 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2023-09-14T10:38:55.159+03:00 INFO 288 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 8 ms. Found 0 JPA repository interfaces.
2023-09-14T10:38:56.647+03:00 INFO 288 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8090 (http)
2023-09-14T10:38:56.669+03:00 INFO 288 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2023-09-14T10:38:56.669+03:00 INFO 288 --- [ restartedMain] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.5]
2023-09-14T10:38:56.787+03:00 INFO 288 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2023-09-14T10:38:56.788+03:00 INFO 288 --- [ restartedMain] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2923 ms
2023-09-14T10:38:56.818+03:00 INFO 288 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2023-09-14T10:38:57.185+03:00 INFO 288 --- [ restartedMain] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@2cf75a85
2023-09-14T10:38:57.186+03:00 INFO 288 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2023-09-14T10:38:57.196+03:00 INFO 288 --- [ restartedMain] o.s.b.a.h2.H2ConsoleAutoConfiguration : H2 console available at '/h2-console'. Database available at 'jdbc:mysql://localhost:3306/testdbgymapp?serverTimezone=UTC'
2023-09-14T10:38:57.461+03:00 INFO 288 --- [ restartedMain] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2023-09-14T10:38:57.676+03:00 INFO 288 --- [ restartedMain] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.1.7.Final
2023-09-14T10:38:57.963+03:00 INFO 288 --- [ restartedMain] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2023-09-14T10:38:58.141+03:00 INFO 288 --- [ restartedMain] SQL dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
2023-09-14T10:38:58.537+03:00 INFO 288 --- [ restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2023-09-14T10:38:58.548+03:00 INFO 288 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2023-09-14T10:38:58.761+03:00 WARN 288 --- [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2023-09-14T10:38:59.336+03:00 INFO 288 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2023-09-14T10:38:59.366+03:00 INFO 288 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8090 (http) with context path ''
2023-09-14T10:38:59.375+03:00 INFO 288 --- [ restartedMain] org.example.App : Started App in 6.016 seconds (process running for 6.52)
2023-09-14T10:51:26.685+03:00 WARN 288 --- [l-1 housekeeper] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Thread starvation or clock leap detected (housekeeper delta=1m59s220ms870µs300ns).
2023-09-14T10:53:55.076+03:00 INFO 288 --- [nio-8090-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2023-09-14T10:53:55.077+03:00 INFO 288 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2023-09-14T10:53:55.079+03:00 INFO 288 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms
排查与解决步骤
修复404错误:确保Controller被Spring扫描到
- 检查
UserController的包路径是否为org.example.controller,你的@ComponentScan只指定了这个路径,包名不匹配会导致Spring无法识别该Controller。 - 简化
App.java配置:删除@EnableJpaRepositories、@ComponentScan、@EntityScan,因为@SpringBootApplication默认扫描主类(App.java)所在包及其子包,只要所有组件都在org.example或其子包下,无需额外配置,避免路径写错。
- 检查
解决连接拒绝:使用模拟器访问本地服务的正确地址
- 安卓模拟器中
localhost/127.0.0.1指向模拟器自身,要访问电脑上的Spring Boot服务,需用专用映射地址http://10.0.2.2:8090/users/login。 - 确认电脑防火墙允许8090端口的入站请求,且电脑与模拟器处于同一局域网。
- 安卓模拟器中
验证请求参数匹配
- 检查Flutter代码中传递的
username、password字段名,是否与后端UserDTO中的字段完全一致(大小写敏感),字段不匹配会导致参数绑定失败。 - 在
application.properties中添加logging.level.web=DEBUG,开启Web请求日志,查看请求是否到达Controller及参数解析情况。
- 检查Flutter代码中传递的

