I am using a yaml file to control the content on my swagger page for my project. I am able to get nearly everything to look correct excepting I want to get the top bar to have the Select a definition drop down (or nothing if that is simpler for now) and not the Explore control. So far I have seen bits and pieces of how to accomplish this but nothing complete, from scratch.
I want this:
...or even this for now:
but NOT this:
Problem is how to create a custom layout in Spring Boot using a custom Swagger YML file? It seems like you need to create a custom layout using React which I know nothing about. Some of the examples of doing a custom layout are pretty straight forward. However, I do not know where to put the file with the React code. In addition, some examples show that ok…yes you need to configure this by pointing to your custom layout in your application.yml file like so:
I don't know what a React file type is postfixed with aka MyLayout.js .jsx or whatever.
I also don't know where to place this custom layout file in the Spring Boot project.
Do I compile it? If so how?
I don't have a solution for a custom header/top bar using a custom Swagger YAML file. However, I achieved it using a custom Springdoc CSS file in one of my projects. To do this, follow these steps:
Load your Swagger UI, open the developer console and navigate to the sources of the page. Download the swagger-ui.css file.
Put this swagger-ui.css file in the resources folder of your Spring Boot project.
Open the swagger-ui.css file and add following CSS (at the bottom of the file) to hide the topbar:
.topbar {
display: none;
}
Create new Controller, which is going to "host" your custom CSS file:
#Controller
public class CustomOpenApiUiController {
#Value("classpath:swagger-ui.css")
private Resource cssFile;
#GetMapping(value = "/swagger-ui/swagger-ui.css")
public void resourceCSS(HttpServletRequest request, HttpServletResponse response) {
setResource(cssFile, response, "text/css;charset=UTF-8");
}
private void setResource(Resource resource, HttpServletResponse response, String contentType) {
try {
response.setHeader("content-type", contentType);
response.setHeader("Pragma", "no-cache");
byte[] file = IOUtils.toByteArray(Objects.requireNonNull(resource.getURI()));
response.getOutputStream().write(file);
} catch (Exception e) {
log.error("Error occurred while loading the OpenAPI CSS file: {}", e.getMessage());
}
}
}
Load your Swagger UI again. The top bar should be gone. You can also check in the developer console, that your new CSS is applied to the .topbar class (which is responsible for the header you are trying to get rid of).
Now that you're in control of the CSS file, you can edit whatever you want.
add groups as follow in
application.yml:
springdoc:
version: '#springdoc.version#'
swagger-ui:
doc-expansion: none
display-request-duration: true
groups-order: ASC
show-actuator: true
group-configs: # add your groups here
- group: all
packagesToScan:
- com.hung.swagger.controller
- group: book
paths-to-match: /store/**
- group: actuator
paths-to-match: /actuator/**
- group: MyRestController
paths-to-match: /api/my-rest-controller/**
- group: MyController
paths-to-match: /api/my-controller/**
Related
Having a maven module that declares a Qute template and REST endpoint to render it, I wanted to include this module on another maven project. The problem is, at it seems, the destination module does not compile since it does not have / find the template in it's resources/templates location (the template is included in the jar of the included module).
Is there any way to instruct Qute (at build time) to read templates from other locations or disable this build check (since the template is in the classpath at the correct location?
The only way I can make it work roght now is to copy my template to the destination project at resources/templates but it doesn't seem the right solution.
Thanks in advance
Yes, by default only the templates located in src/main/resources/templates are validated and can be injected.
You can parse any template content manually via Engine.parse() or even add a custom template locator via io.quarkus.qute.EngineBuilder.addLocator(), e.g. something like:
import io.quarkus.qute.EngineBuilder;
class MyEngineConfig {
void configureEngine(#Observes EngineBuilder builder) {
builder.addLocator(path -> Optional.of(new TemplateLocation() {
#Override
public Reader read() {
return new BufferedReader(new InputStreamReader(FlowChartResource.class.getResourceAsStream(path)));
}
#Override
public Optional<Variant> getVariant() {
return Optional.empty();
}
}));
}
}
The disadvantage is that Quarkus can't validate/inject such templates.
See also related issues https://github.com/quarkusio/quarkus/issues/12084 and https://github.com/quarkusio/quarkus/issues/10376.
Ok, I found another solution, using "low-level" engine instance and parsing the template "manualy":
engine.parse(new BufferedReader(new InputStreamReader(FlowChartResource.class.getResourceAsStream([PATH to My Template]))).lines().collect(Collectors.joining("\n")))
How can I keep links in my UI templates (e.g. Thymeleaf templates) in sync with the corresponding request mappings in my Spring application?
I've seen that e.g. the Play framework uses the #router-Object within its templates. How is it solved by Spring?
One example:
Spring Controller - simple
#Controller
public class UserController {
#GetMapping("/users/{username}")
public String getUser(#PathParam String username) {
// do some stuff....
return "user";
}
}
HTML-Page
<body>
User details
</body>
Now I want to change "/users" to "/accounts". I'm pretty sure that I've got to update every html page by hand to update the link. Is there an easier solution for this?
As far as I know, there is no simple way to do this with built-in tools from Spring. However, I don't think that this would be too hard to build. You would need the following:
A YAML file with all of your URL templates defined
A Properties Spring bean that contains your URL mappings (read from the YAML file)
All of your #RequestMapping annotations would have to be prop values; i.e.
#GetMapping("${urls.users.byUsername}")
A custom tag that knows about the Properties bean and can create URLs from the templates that were defined in your YAML file.
Updated: to describe the question more clearly
I create a web applicaiton with spring boot and thymeleaf, everything works fine if I open the login page, then login, then head for the management module or reports module sequently.
The proleam occurs when I type the url locahost:8080/send/kf/index(needs to authenticate, but I have open access to all in customized filter) in the browser, the page loads without js and css. In debug mode, I saw /send/kf was unexpectly put into the path like the following. I can get the resource if I access localhost:8080/assets/avatars/avatar.png.
The following is the folder structure I put my static resources. How could /send/kf automatically added into the url, please help me solve this problem. Thanks!
you can use spring.resources.static-locations in your application.properties file
spring.resources.static-locations=classpath:/resources/css/
spring.mvc.static-path-pattern=/resources/**
this is taken form documentation
Note:Static resources, like JavaScript or CSS, can easily be served from your Spring Boot application just be dropping them into the right place in the source code. By default Spring Boot serves static content from resources in the classpath at "/static" (or "/public")
Using /assets/ instead of assets/ fixes the issue, as otherwise it's a relative url that's supposed to get added to the end of existing url.
I find a solution for this question. I don't know how /send/kf is put into the url for the static resources, but I think if I put the controller mapping under the root path, this problem should avoid. As I think, the url is correct and resources can load successfully.
#Controller
public class ManualMessageController {
#Autowired
private MsgTemplateRepository msgTemplateRepository;
#RequestMapping("/manualMsg")
public String manualMsg(Model model){
model.addAttribute("msgTemplateList", msgTemplateRepository.findByStatus(1));
return "manualMessage";
}
}
updated:
The right solution is to use absolute path rather than relative path in the project. So change assets/css to /assets/css works.
I am using Spring Boot 2.0.0 M1 with WebFlux to build my sample web application. After succeeding with REST endpoints I've decided to add some views to my application. I've decided to use Thymeleaf 3.x version. I know that Spring serves static content from 4 default location:
/META-INF/resources/
/resources/
/static/
/public/
I've decided to go with second example so my css file is in /resources/static/css/. However after loading my page .css file was not found.
This is a screenshot from my IDE:
I am not providing my own configuration for static directory I just want to use default one. What might be important is the fact that templates are loading just fine from the /resources/templates/ directory.
Css file is loaded like this:
<link data-th-href="#{css/bootstrap.min.css}" rel="stylesheet">
App is not using normal Controller class instead I've provided function as a Bean to define my router:
#Bean
RouterFunction<?> router(final GeneratorHandler generatorHandler) {
return route(GET("/generate"), handler::render);
}
Any ideas what's wrong here?
I've found the right solution. In your RouterFunction you need to use:
return resources("/**", new ClassPathResource("/static/"))
This will set your static directory to:
:classpath/static
I have an empty project created using GGTS, my app runs fine, I can see the views and navigate through them fine.
I need con call a REST api and consume the data provided, I read and added the necessary plug in to the BuildConfig file under the dependencies and then under the plugins section, none of them seem to work.
compile ":rest-client-builder:2.0.0"
I've created a controller, I'm not sure where to add the import here, so I've tried:
package myapp
class UserController {
def index() {
import grails.plugins.rest.client.RestBuilder
String url = "https://foo.com/batch/$id"
def resp = new RestBuilder().get(url) { header 'Authorization', 'Basic base64EncodedUsername&Password' }
render resp
}
but I get the error: unable to resolve class....
The API is returning JSON data, what I;ve done so far is just to create a new Grails project, add controller, add view and then the dependency.
I've cleaned an built the project several times but the error remains.
Thanks for your help.
Import goes at the top
After the package line
And before the class line
Also, depending on your version of grails, you might want to move of ggts... Not sure it's supported any more...
I think that the problem is in your build.gradle dependency definition.
Insert the next line to your build.gradle file and I think that will be helpful:
compile "org.grails.plugins:rest-client-builder:2.1.1"
For more information follow the grails plugin documentation.
Please be aware that all the business logic should be placed in the service layer and not in the controller. It is a best practice to keep your controller lean as possible.
Another best practice is to define the following line:
String url = "https://foo.com/batch/$id"
in the beggining of the controller as static final String
static final String url = "https://foo.com/batch/"
and add the $id when needed in the code.
Here is how that should be called inside the method:
String url = "${url}/{$id}"