I'm attempting to pull two parameters with the #PathVariable annotation but have been unsuccessful due to java throwing me an error about it referencing the item id (which I currently has as an Long) as a String.
Controller:
#PostMapping("/purchaseToner/{tid}/{bid}")
public String buyToner(Model model, #PathVariable("tid") Long tid,
#PathVariable("bid") Long bid){
//Grab info
Buyer mBuyer = buyerService.findOne(bid);
Toner mToner = tonerService.findOneToner(tid);
//Updating qualities
mToner.setTonerQuantity(mToner.getTonerQuantity() - 1);
mBuyer.setBalance(mBuyer.getBalance() - mToner.getTonerPrice());
Buyer iBuyer = new Buyer();
iBuyer.getToners().add(mToner);
return "redirect:/";
}
View:
<form th:action="#{/purchaseToner/{tid}(tid=${toner.id})/{bid}(bid=${buyer.buyerId})}" th:object="${buyer}" method="post">
<select th:object="${toner}">
<option>Select a Toner</option>
<option th:each="toner : ${toners}"
th:text="${toner.tonerName}"
th:value="${toner.id}">
</option>
</select>
<input type="hidden" name="buyerId"/>
<input type="submit" value="Purchase" onclick="return confirm('Are you sure you want to make this purchase?')"/>
</form>
Print Trace:
2017-06-05 21:10:59.418 INFO 788 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2017-06-05 21:10:59.517 INFO 788 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-06-05 21:10:59.527 INFO 788 --- [ main] com.ronone.Application : Started Application in 18.596 seconds (JVM running for 19.548)
2017-06-05 21:11:06.438 INFO 788 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-06-05 21:11:06.439 INFO 788 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2017-06-05 21:11:06.470 INFO 788 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 31 ms
2017-06-05 21:11:09.673 INFO 788 --- [nio-8080-exec-2] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
2017-06-05 21:11:15.837 WARN 788 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to bind request element: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "{tid}(tid=${toner.id})"
Your api buyToner has not been receiving inputs in path variable as number. There is nothing wrong with your api service; check your client side code, is it sending request in proper format OR have you tested your api with any restclient ?
Check out the java exception
java.lang.NumberFormatException: For input string: "{tid}(tid=${toner.id})"
input is not a number here. AND WHY ?
Try to change this:
#PostMapping("/purchaseToner/{tid}/{bid}")
public String buyToner(Model model, #PathVariable("tid") Long tid,
#PathVariable("bid") Long bid){
...
}
into this:
#PostMapping("/purchaseToner/{tid}/{bid}")
public String buyToner(Model model, #PathVariable("tid") String tid,
#PathVariable("bid") String bid){
long bidlong = Long.parseLong(bid)
long tidlong = Long.parseLong(tid)
//Grab info
Buyer mBuyer = buyerService.findOne(bid);
Toner mToner = tonerService.findOneToner(tid);
...
}
In other words, change your controller's parameters into String types, then convert them into Long.
Change th:action to following
<form th:action="#{/purchaseToner/{tid}/{bid}(tid=${toner.id},bid=${buyer.buyerId})}" th:object="${buyer}" method="post">
Also, you need to add toner to spring model. In your code, It is not in the model
Related
I have a controller with an endpoint that provide a flux like this reported below.
When the app is deployed to kubernetes, methods doOnCancel and doOnTerminate are not invoked.
Locally instead, it works like a charm (when the tab of the browser is closed as instance).
#Slf4j
#RestController
public class TestController {
...
#GetMapping(value = "/test", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> testStream() {
log.info("Requested test streaming");
return mySink.asFlux()
.startWith("INIT TEST")
.doOnCancel(() -> log.info("On cancel"))
.doOnTerminate(() -> log.info("On terminate"));
}
...
}
2022-08-06 18:25:42.115 INFO 3685 --- [ main] com.wuase.sinkdemo.SinkDemoApplication : Starting SinkDemoApplication using Java 1.8.0_252 on aniello-pc with PID 3685 (/home/pc/eclipse-workspace/sink-demo/target/classes started by pc in /home/pc/eclipse-workspace/sink-demo)
2022-08-06 18:25:42.124 INFO 3685 --- [ main] com.wuase.sinkdemo.SinkDemoApplication : No active profile set, falling back to 1 default profile: "default"
2022-08-06 18:25:44.985 INFO 3685 --- [ main] o.s.b.web.embedded.netty.NettyWebServer : Netty started on port 8080
2022-08-06 18:25:45.018 INFO 3685 --- [ main] com.wuase.sinkdemo.SinkDemoApplication : Started SinkDemoApplication in 3.737 seconds (JVM running for 5.36)
2022-08-06 18:26:09.706 INFO 3685 --- [or-http-epoll-3] com.wuase.sinkdemo.TestController : Requested test streaming
2022-08-06 18:26:14.799 INFO 3685 --- [or-http-epoll-3] com.wuase.sinkdemo.TestController : On cancel
Has anyone encountred the same problem?
Any idea about that?
I have a Java Spring Boot application (Java 8 JDK) that makes calls to a REST service. For the delete resource case, I need to specify the path as follows: /api/v4/projects/<URL encoded project path>, where the project path is typically represented as a parent "group" followed by the project name. For example: my-group/my-project. So, when I invoke the delete case, the example path needs to be my-group%2Fmy-project.
I am using java.net.URLEncoder.encode(value, StandardCharsets.UTF_8.toString()) to do the encoding and it converts the example path to what it needs to be (the group is test and the project is test-cold-storage):
https://<removed>/api/v4/projects/test%2Ftest-cold-storage
When I invoke the call, however, it fails. I have an interceptor that prints out the details of the request being made. It's showing something unexpected.
2022-07-18 15:49:18.030 INFO 21888 --- [ main] c.b.d.c.c.CustomRequestInterceptor : Request:
2022-07-18 15:49:18.030 INFO 21888 --- [ main] c.b.d.c.c.CustomRequestInterceptor : URI: https://<removed>/api/v4/projects/test%252Ftest-cold-storage
2022-07-18 15:49:18.030 INFO 21888 --- [ main] c.b.d.c.c.CustomRequestInterceptor : Method: DELETE
It looks like it's being encoded again (maybe?). 0x25 = '%' and 0x2F = '/'. If I do it without encoding the group/path, no encoding occurs and it fails again.
2022-07-19 07:47:02.146 INFO 5200 --- [ main] c.b.d.c.c.CustomRequestInterceptor : Request:
2022-07-19 07:47:02.147 INFO 5200 --- [ main] c.b.d.c.c.CustomRequestInterceptor : URI: https://<removed>/api/v4/projects/test/test-cold-storage
2022-07-19 07:47:02.147 INFO 5200 --- [ main] c.b.d.c.c.CustomRequestInterceptor : Method: DELETE
Has anyone else run into this? Is there some setting in the configuration of the RestTemplate object that affects this?
UPDATE
I have managed to trace execution in the debugger and found that it is encoding the URL. This is happening in org.springframework.web.util.DefaultUriBuilderFactory.createURI().
I don't know if this information is helpful.
Figured it out. I needed to pass the project path (i.e. test/test-cold-storage) as a URI variable instead of tacking it on the end of the URL. The endpoint URL need to change as follows:
String endpointURL = baseURL + GITLAB_REST_API + "projects/{path}";
and the delete call changed to add URI variable (projectPath):
template.delete(endpointURL, projectPath);, where in this example projectPath is test/test-cold-storage.
I'm new to spring framework and REST, and now trying to migrate REST from jersey to spring boot 2.1
The controller works fine with jax-rs, however, I don't want to use jax-rs in spring boot. So, I tried spring Mvc and I get 'resource not found' error. Please I'd really appreciate any help.
I tried this
#GetMapping(value ="/generic/download_file/{path:[^\\.+]*}", consumes ="application/vnd.X-FileContent")
public ResponseEntity<?> downloadFile(#PathVariable("path") String filePath){
String actualFilePath = "";
try {
actualFilePath = filePath.replaceAll("\\/", "\\\\");
File file = new File(actualFilePath);
if (file.exists()) {
return ResponseEntity.ok().header("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"").body(file);
} else {
return errorHandling.errorResponseFactory("1.0.0", Thread.currentThread().getStackTrace()[1], "",
RecommendedSolution.UseValidDirectoryPath, "File not exist.");
}
} catch (Exception ex) {
ActionLog.writeLog("program_library_v510", "1.0.0", "Exception occur during gettig generic package file",
ActionLogType.DebugLog);
ActionLog.writeLog("program_library_v510", "1.0.0", "Exception occur during getting generic package file",
ActionLogType.ErrorLog);
return errorHandling.errorResponseFactory("1.0.0", Thread.currentThread().getStackTrace()[1], "",
RecommendedSolution.UnexpectedErrorMsg, "");
}
}
2019-01-07 17:17:23.930 INFO 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : Completed initialization in 10 ms
2019-01-07 17:17:23.947 DEBUG 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : GET "/packages/download_file/D:/xfolder/test.txt", paramete
rs={}
2019-01-07 17:17:24.002 DEBUG 13664 --- [nio-9090-exec-2] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/
resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2019-01-07 17:17:24.006 DEBUG 13664 --- [nio-9090-exec-2] o.s.w.s.r.ResourceHttpRequestHandler : Resource not found
2019-01-07 17:17:24.007 DEBUG 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : Completed 404 NOT_FOUND
2019-01-07 17:17:24.015 DEBUG 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : "ERROR" dispatch for GET "/error", parameters={}
2019-01-07 17:17:24.029 DEBUG 13664 --- [nio-9090-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServ
letRequest)
2019-01-07 17:17:24.077 DEBUG 13664 --- [nio-9090-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json', given [/] and supported [applic
ation/json, application/+json, application/json, application/+json]
2019-01-07 17:17:24.078 DEBUG 13664 --- [nio-9090-exec-2] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Writing [{timestamp=Mon Jan 07 17:17:24 SGT 2019, status=40
4, error=Not Found, message=No message available, path=/packages/download_file/D:/xfolder/test.txt}]
2019-01-07 17:17:24.146 DEBUG 13664 --- [nio-9090-exec-2] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 404
I suspect two things here. Let me clarify this.
What is the API url you are calling?
/generic/download_file/{path:[^\\.+]*} or /packages/download_file/D:/xfolder/test.txt
both are looks different. Please see generic and packages
The better way to pass filenames in URL is using #RequestParam instead of #PathVariable
#GetMapping(value ="/generic/download_file/", consumes ="application/vnd.X-FileContent")
public ResponseEntity downloadFile(#RequestParam("path") String filePath){
I am trying to use kafka with camel and set up the following route:
public class WorkflowEventConsumerRoute extends RouteBuilder {
private static final String KAFKA_ENDPOINT =
"kafka:payments-bus?brokers=localhost:9092";
...
#Override
public void configure() {
from(KAFKA_ENDPOINT)
.routeId(format(KAFKA_CONSUMER))
.to("mock:end);
}
}
When I start my spring boot application I can see the route gets started but immediately after this it shuts down without any reasons given in the logs:
2018-12-21 12:06:45.012 INFO 12184 --- [ main] o.a.kafka.common.utils.AppInfoParser : Kafka version : 2.0.1
2018-12-21 12:06:45.013 INFO 12184 --- [ main] o.a.kafka.common.utils.AppInfoParser : Kafka commitId : fa14705e51bd2ce5
2018-12-21 12:06:45.014 INFO 12184 --- [ main] o.a.camel.spring.SpringCamelContext : Route: kafka-consumer started and consuming from: kafka://payments-bus?brokers=localhost%3A9092
2018-12-21 12:06:45.015 INFO 12184 --- [r[payments-bus]] o.a.camel.component.kafka.KafkaConsumer : Subscribing payments-bus-Thread 0 to topic payments-bus
2018-12-21 12:06:45.015 INFO 12184 --- [ main] o.a.camel.spring.SpringCamelContext : Total 1 routes, of which 1 are started
2018-12-21 12:06:45.015 INFO 12184 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.23.0 (CamelContext: camel-1) started in 0.234 seconds
2018-12-21 12:06:45.019 INFO 12184 --- [ main] a.c.n.t.p.workflow.WorkflowApplication : Started WorkflowApplication in 3.815 seconds (JVM running for 4.513)
2018-12-21 12:06:45.024 INFO 12184 --- [ Thread-10] o.a.camel.spring.SpringCamelContext : Apache Camel 2.23.0 (CamelContext: camel-1) is shutting down
On the other hand if create an unit test and point to the same kafka endpoint I am able to read the kafka topic content using the org.apache.camel.ConsumerTemplate instance provided by the CamelTestSupport
Ultimately if I replace the kafka endpoint in my route with an activemq one the route starts OK and the application stays up.
Obviously I am missing something but I cannot figure out what.
Thank you in advance for your help.
Do your spring-boot app have a -web-starter or not. If not then you should turn on the camel run-controller to keep the boot application running.
In the application.properties add
camel.springboot.main-run-controller = true
I have a simple Spring-Boot web application with some scheduling tasks:
#SpringBootApplication
#EnableScheduling
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder app) {
return app.sources(Application.class);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
And a service executing two scheduling tasks:
#Service
public class SchedulingService {
#Scheduled(fixedRate = 15000)
private void first() {
// log first
}
#Scheduled(fixedRate = 6000)
public void second() {
// log second
}
}
Is there any explanation revealing why one of the scheduling tasks has been executed before the application and servlet starts up? This happens repeatedly and the log order is always the same, so I suspect the multithreading doesn't take place - there is nearly one-second difference between the first and the second scheduling task.
Here is the log with highlighted parts of the scheduling task log:
2018-08-18 20:47:53.085 INFO 251168 --- [ost-startStop-1] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
2018-08-18 20:47:53.300 INFO 251168 --- [ost-startStop-1] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-08-18 20:47:53.314 INFO 251168 --- [ost-startStop-1] s.a.ScheduledAnnotationBeanPostProcessor : No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
2018-08-18 20:47:53.321 HERE LOGGED FIRST
2018-08-18 20:47:53.344 INFO 251168 --- [ost-startStop-1] my.appname.Application : Started Application in 5.565 seconds (JVM running for 16.93)
2018-08-18 20:47:53.396 INFO 251168 --- [ main] org.apache.coyote.ajp.AjpNioProtocol : Starting ProtocolHandler ["ajp-nio-8009"]
2018-08-18 20:47:53.400 INFO 251168 --- [ main] org.apache.catalina.startup.Catalina : Server startup in 15970 ms
2018-08-18 20:47:53.477 INFO 251168 --- [nio-8080-exec-1] o.a.c.c.C.[.[localhost].[/Rattle] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2018-08-18 20:47:53.477 INFO 251168 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2018-08-18 20:47:53.520 INFO 251168 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 43 ms
2018-08-18 20:47:54.103 HERE LOGGED SECOND
2018-08-18 20:47:59.335 HERE LOGGED SECOND
2018-08-18 20:48:05.334 HERE LOGGED SECOND
2018-08-18 20:48:08.334 HERE LOGGED FIRST
I just created an empty SpringBoot project, added your class and tried to reproduce the same issue.
On SpringBoot 2.0.4.RELEASE I see that both tasks run at the same time and same thread:
2018-08-18 21:16:54.145 INFO 10239 --- [pool-1-thread-1] com.test.SchedulingService : LOG FIRST
2018-08-18 21:16:54.145 INFO 10239 --- [pool-1-thread-1] com.test.SchedulingService : LOG SECOND
Then, I added a Thread.sleep(100) on the both tasks as I cannot predict the execution order.
2018-08-18 21:21:14.775 INFO 10274 --- [pool-1-thread-1] com.test.SchedulingService : LOG FIRST
2018-08-18 21:21:14.878 INFO 10274 --- [pool-1-thread-1] com.test.SchedulingService : LOG SECOND
The delay of aprox 100ms between the log entries, confirm that they run on the same thread.
You might think that setting the initialDelay = 0 on the #Scheduled might help, but it will not; everything will still be on the main thread.
The solution I found is defining a custom bean that creates a customTaskScheduler:
#Bean()
public ThreadPoolTaskScheduler taskScheduler(){
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(2);
taskScheduler.setThreadNamePrefix("Async-");
return taskScheduler;
}
Now, the logs show that both tasks are executed at the same time and by different threads:
2018-08-18 21:30:26.482 INFO 10383 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2018-08-18 21:30:26.486 INFO 10383 --- [ main] com.test.ProjectApplication : Started ProjectApplication in 1.767 seconds (JVM running for 2.137)
2018-08-18 21:30:26.555 INFO 10383 --- [ Async-2] com.test.SchedulingService : LOG SECOND
2018-08-18 21:30:26.555 INFO 10383 --- [ Async-1] com.test.SchedulingService : LOG FIRST
I defined a thread pool of size = 2. What will happen if I have 3 tasks to run? One of the tasks will need to wait to complete the execution of the previous 2, get the thread released and check the execution queue again.
2018-08-18 21:33:48.895 INFO 10412 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2018-08-18 21:33:48.899 INFO 10412 --- [ main] com.test.ProjectApplication : Started ProjectApplication in 1.888 seconds (JVM running for 2.258)
2018-08-18 21:33:48.960 INFO 10412 --- [ Async-1] com.test.SchedulingService : LOG FIRST
2018-08-18 21:33:48.960 INFO 10412 --- [ Async-2] com.test.SchedulingService : LOG SECOND
2018-08-18 21:33:49.065 INFO 10412 --- [ Async-2] com.test.SchedulingService : LOG THIRD
I had same issue, but I was able to get around it by specifying the cron parameter instead of using fixedRate or fixedRateString like so #Scheduled(cron = "0 0 4 ? * SUN,THU")
More details on using the cron expression in spring-boot can be found here https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/support/CronExpression.html