Witam. Mam problem z aplikacją. Mam utworzone 2 serwisy, z których jeden (db-connector) łączy się z bazą danych i pozwala na pewne akcje (używam Postmana, aby określać mappingi), a drugi (webApp) używany poprzez przeglądarkę łączy się z pierwszym.
db-connector :
@RestController
public class HelloWorldController {
@Autowired
private UserDataAccess userDataAccess;
@DeleteMapping(path = "/user")
public void deleteUser(@RequestParam(name = "identyfikator") long userId) {
userDataAccess.deleteUserById(userId);
}
@PatchMapping(path = "/user")
public void updateUser(@RequestParam(name = "identyfikator") long userId, @RequestBody String password) {
userDataAccess.updateUserPasswordById(userId, password);
}
@PostMapping(path = "/createUser")
public String createUser(@RequestParam(name = "userLogin") String login, @RequestParam(name = "password") String password,
@RequestParam(name = "firstName") String firstName, @RequestParam(name = "lastName") String lastName) {
createUserMethod(login, password, firstName, lastName);
return login + " " + password + " " + firstName + " " + lastName + " ";
}
private User createUserMethod(String login, String password, String firstName, String lastName) {
User user = UserBuilder.anUser().withLogin(login).withPassword(password).withFirstName(firstName).withLastName(lastName).build();
userDataAccess.createUser(user);
return user;
}
}
//=================================== klasy znajdują się w oddzielnych plikach. Dla ułatwienia wstawiłem jedną pod drugą ;)
@Service
public class UserDataAccess {
private final String INSERT_SQL = "INSERT INTO EXAMPLE_SCHEMA.USERS(login, password, first_name, last_name) values(:login, :password, :first_name, :last_name)";
private final String UPDATE_SQL = "UPDATE EXAMPLE_SCHEMA.USERS SET password = :password WHERE id = :userId";
private final String DELETE_SQL = "DELETE EXAMPLE_SCHEMA.USERS WHERE id = :userId";
@Autowired
NamedParameterJdbcTemplate namedParameterJdbcTemplate;
public void createUser(User user) {
KeyHolder holder = new GeneratedKeyHolder();
SqlParameterSource parameters = new MapSqlParameterSource()
.addValue("login", user.getLogin())
.addValue("password", Base64.getEncoder().encodeToString(user.getPassword().getBytes()))
.addValue("first_name", user.getFirstName())
.addValue("last_name", user.getLastName());
namedParameterJdbcTemplate.update(INSERT_SQL, parameters, holder);
user.setId(holder.getKey().intValue());
}
public void deleteUserById(long userId) {
SqlParameterSource parameter = new MapSqlParameterSource()
.addValue("userId", userId);
namedParameterJdbcTemplate.update(DELETE_SQL, parameter);
}
public void updateUserPasswordById(long userId, String password) {
SqlParameterSource parameter = new MapSqlParameterSource()
.addValue("userId", userId)
.addValue("password", Base64.getEncoder().encodeToString(password.getBytes()));
namedParameterJdbcTemplate.update(UPDATE_SQL, parameter);
}
private static final class UserMapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
return UserBuilder.anUser()
.withId(rs.getLong("id"))
.withLogin(rs.getString("login"))
.withPassword(rs.getString("password"))
.withFirstName(rs.getString("first_name"))
.withLastName(rs.getString("last_name"))
.build();
}
}
}
I tak to wygląda to w 1. serwisie. Podałem najważniejsze metody, które są odpowiedzialne za pożądane funkcje aplikacji.
Poprzez Postmana wszystko działa: tworzenie, usuwanie i zmiana hasła. Problem zaczyna się, gdy chcę obsłużyć to przez przeglądarkę.
webApp
@Controller
public class HomeController {
RestTemplate restTemplate = new RestTemplate();
@GetMapping("/welcome")
public String homePage() {
return "welcome";
}
@GetMapping("/delete")
public String goToDelete(Model model) {
model.addAttribute("user", new User());
return "delete";
}
@DeleteMapping("/delete")
public String deleteUser(@ModelAttribute("searchingQuery") SearchingQuery searchingQuery, Model model) {
User user = restTemplate.getForObject("http://localhost:8080/user?identyfikator=" + searchingQuery.getById(), User.class);
if(user == null) {
model.addAttribute("user", new User());
} else {
model.addAttribute("user", user);
}
return "delete";
}
@GetMapping("/updatePassword")
public String goToUpdatePassword() {
return "updatePassword";
}
@PatchMapping("/updatePassword")
public String updatePasswordById(@ModelAttribute("createQuery") CreateQuery createQuery, Model model) {
User user = restTemplate.getForObject("http://localhost:8080/user?identyfikator=" + createQuery.getId(), User.class);
if(user == null) {
model.addAttribute("user", new User());
} else {
model.addAttribute("user", user);
}
return "updatePassword";
}
@GetMapping("/createUser")
public String goToCreateUser() {
return "createUser";
}
@PostMapping("/createUser")
public String createUser(@ModelAttribute("createQuery") CreateQuery createQuery) {
User user = restTemplate.getForObject("http://localhost:8080/createUser?userLogin=" + createQuery.getLogin()
+ "&password=" + createQuery.getPassword() + "&firstName=" + createQuery.getFirstName()
+ "&lastName=" + createQuery.getLastName(), User.class);
return "createUser";
}
}
Pliki html (webApp) (podaje samo ciało)
createUser.html
<body>
<div class="container">
<form th:action="@{/createUser}" th:object="${createQuery}" method="post">
<div class="row mt-3">
<div class="col">
<span class="input-group-text" id="inputGroup-sizing-default">| Tworzenie użytkownika |</span>
</div>
<span class="input-group-text" id="inputGroup-sizing-default2">login:</span>
<div class="col">
<input type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" id="login" name="login">
</div>
<span class="input-group-text" id="inputGroup-sizing-default3">hasło:</span>
<div class="col">
<input type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" id="password" name="password">
</div>
<span class="input-group-text" id="inputGroup-sizing-default4">imię:</span>
<div class="col">
<input type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" id="firstName" name="firstName">
</div>
<span class="input-group-text" id="inputGroup-sizing-default5">nazwisko:</span>
<div class="col">
<input type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" id="lastName" name="lastName">
</div>
<div class="col">
<button class="btn btn-primary" type="submit">Wprowadź</button>
</div>
</div>
</form>
</div>
delete.html
<div class="container">
<form th:action="@{/delete}" th:object="${searchingQuery}" method="post">
<div class="row">
<div class="col">
<span class="input-group-text" id="inputGroup-sizing-default">Wprowadź ID</span>
</div>
<div class="col">
<input type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" id="byId" name="byId">
</div>
<div class="col">
<button class="btn btn-primary" type="submit">Usuń</button>
</div>
</div>
</form>
</div>
*Klasy SearchingQuery i CreateQuery zawierają pola takie jak klasa User (login, password, itd.)
Przy tworzeniu użytkownika po wciśnięciu Wprowadź, w konsoli wywala błąd:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpClientErrorException$MethodNotAllowed: 405 : [{"timestamp":"2020-09-10T10:59:33.281+00:00","status":405,"error":"Method Not Allowed","message":"","path":"/createUser"}]] with root cause
org.springframework.web.client.HttpClientErrorException$MethodNotAllowed: 405 : [{"timestamp":"2020-09-10T10:59:33.281+00:00","status":405,"error":"Method Not Allowed","message":"","path":"/createUser"}]
Natomiast odnośnie usuwania wywala błąd:
2020-09-10 13:06:17.200 WARN 9000 --- [nio-8081-exec-9] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
Gdy staram się dodać w kontrolerze do metody odpowiedzialnej za usuwanie @PostMapping aplikacja łapie to jako inną metodę z POSTEM z członem /user (której tutaj dla ułatwienia nie podałem). Nie wiem jak to rozwikłać, ponieważ w HTML w formie method nie może przyjąć argumentu "delete".
Trochę tego kodu tutaj dużo, ale chciałem jak najlepiej zobrazować problem, ponieważ już dłuższy czas siedzę przed ścianą i nie znalazłem żadnego rozwiązania powyższych problemów.
Pozdrawiam :)