0

I mean, this is what i have in my code:

@GetMapping("/get/player/{csvName}")
public void loadPlayers(@PathVariable String csvName) {
/*Irrelevant code here*/
}

This works just because the csv file is in the root of my project.

Is there any way to set the relative path of the csv file on the url?

////////////////////////////////////////////////////EDIT///////////////////////////////////////////////////////

Here is the code of the class:

@RestController
@RequestMapping("/csv")
public class CsvController {
    
    
    private static final Logger log = LoggerFactory.getLogger(FutbolApplication.class);
    
    @Autowired
    private PlayerRepository playerRepository;
    @Autowired
    private TeamRepository teamRepository;
    @Autowired
    private MembershipRepository memberRepository;
    
    
    @GetMapping("/get/player/{csvName}")
    public void loadPlayers(@PathVariable String csvName) {
        
        CSVReader reader;
        try {
            reader = new CSVReaderBuilder(new FileReader(csvName))
                    .withSkipLines(1).build();

            String[] values;
            int i;
            int count=0;
            while ((values = reader.readNext()) != null) {
                count++;
                i=0;
                try {
                Player player = new Player(values[i++],values[i++],values[i++],Date.valueOf(values[i++]));
                System.out.println(player.getName() + "//" + player.getSurname() + "//" + player.getPosition()
                        + "//" + player.getBirthDate());
                playerRepository.save(player);
                }catch (Exception e) {
                    log.error("ERROR INTENTANDO ASIGNAR LOS DATOS AL JUGADOR "+(count));
                }
            }

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (CsvValidationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

What I can to, is to insert the path of the csv instead of just the name.

At the moment my project's structure is:

>project
    >src
       >main
       >test
    >.Settings
    >mycsvfile.csv

that's why i can just type "mycsvfile.csv" in the url and it works

But this is what i'd like to get:

>project
    >src
       >main
       >test
    >.Settings
    >csvs
       >mycsvfile.csv

And get it to work by typing "/csvs/mycsvfile.csv"

Because now i just can type "https:localhost:8080/csv/get/player/mycsvfile.csv"

Is it possible?

  • Here, csvName is just a string variable. Nothing about the path of a file. Maybe the code you're hiding will help more with your problem. – Sergio Lema Oct 05 '22 at 15:57
  • Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Oct 06 '22 at 03:33
  • i've edited the post, check it out please. – David Ruiz Oct 06 '22 at 09:29

1 Answers1

0

Use @RequestParam instead of @PathVariable.

If I understood correctly, you want to send the path of the file, you want to load your Player from, via the request.

Sending a file path in the URI won't work from the get go as it will change the path of the request and it will lead to a 404 NOT FOUND.

Using @RequestParam is a different story, you can add full file path there.

@GetMapping("/get/player")
public void loadPlayers(@RequestParam String csvName) {
    /*Rest of your code here*/
}

This way your request would look like this:

https://localhost:8080/csv/get/player?csvName=csvs/mycsvfile.csv

If you really want to use @PathVariable to send the path of your file, then you will have to change your endpoint to work with wildcard and extract the file path from the request URI like explained by N. Chicoine here.

And if you need to use this in multiple places you can even get a more elegant solution by implementing an annotation that makes use of the HandlerMethodArgumentResolver interface:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface FilePath {

    class Resolver implements HandlerMethodArgumentResolver {

        private final PathMatcher pathMatcher;

        public Resolver() {
            this.pathMatcher = new AntPathMatcher();
        }

        @Override
        public boolean supportsParameter(MethodParameter methodParameter) {
            Annotation annotation = methodParameter.getParameterAnnotation(FilePath.class);
            return annotation != null;
        }

        @Override
        public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modeContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
            HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
            if (servletRequest == null) {
                return null;
            }
            String patternAttribute = (String) servletRequest.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
            String mappingAttribute = (String) servletRequest.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
            return this.pathMatcher.extractPathWithinPattern(patternAttribute, mappingAttribute);
        }
    }
}

Then you will have to register the annotation in application configuration:

@Configuration
public class Config implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new FilePath.Resolver());
    }
}

And finaly you can use it like this:

    @GetMapping("/get/player/**")
    public void loadPlayers(@FilePath String csvName) {
        /*Rest of your code here*/
    }

Enabling you to execute the request like:

https://localhost:8080/csv/get/player/csvs/mycsvfile.csv

Hope this will help you.