I have a java application that allows users to upload documents. The uploaded docs are saved on a network in a specific "client-files" folder and logged in the SQL database in a document storage table. Adding them the the specific file on the network is working accurately, but when I click to download (aka view) the file from the applicataion in the browser, it is returning a 404 error. The url is accurate, and I am not sure where to start with trouble shooting this issue. Any idea, what I should be looking at as to why this isn't working? Clearly the paths are set up correctly since I can download from the app to the storage file. Just not sure what is blocking it from sending it back. Can it be something on the server side?
Also, not sure what code you'd need to know to look at this. This is the download button....
<td>
<span>
<span th:text="${doc.storage}"></span>
<a th:href="#{|/client-files/${client.principleName+' '+client.id+'/'+doc.storage}|}"><i class="fa fa-download"/></a>
</span>
</td>
It doesn't look like the code base has a controller for the viewing aspect. It appears it is just appending the link and supposed to access the folder/files via calling the link?
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/client-files/**").addResourceLocations("file:client-files/");
registry.addResourceHandler("/client-files/**").addResourceLocations("file:carrier-files/");
}
#Controller
public class DocumentsController {
#Autowired
ClientRepository clientRepository;
#Autowired
LicenseRepository licenseRepository;
#Autowired
DocumentRepository documentRepository;
#Autowired
StorageService storageService;
#Autowired
DocumentService documentService;
#Autowired
InsuranceRepository insuranceRepository;
#Autowired
CarrierAppointmentRepository carrierAppointmentRepository;
#Autowired
RoleRepository roleRepository;
#RequestMapping(value="/documents/client/{id}")
public String manageDocuments(Model model, #PathVariable("id") Client client){
Document newDocument=new Document();
License newLicense=new License();
Insurance newInsurance=new Insurance();
model.addAttribute("insurances",insuranceRepository.findByClient(client));
model.addAttribute("newDocument",newDocument);
model.addAttribute("newLicense",newLicense);
model.addAttribute("newInsurance",newInsurance);
model.addAttribute("licenses",licenseRepository.findByClient(client));
model.addAttribute("docs",documentRepository.findByClient(client));
model.addAttribute("client",client);
return "documents";
}
#RequestMapping(value="/save/document")
public String addDoc(Model model, #ModelAttribute(value="newDocument") Document newDocument, #RequestParam("document") MultipartFile file){
Document doc=documentRepository.save(newDocument);
doc.setStorage(storageService.store(file,newDocument.getClient()));
documentRepository.save(doc);
documentService.markDocuments(newDocument.getClient(),newDocument.getType());
return "redirect:/documents/client/"+newDocument.getClient().getId();
}
#RequestMapping(value="/delete/doc/{id}")
public String deleteDoc(Model model, #PathVariable("id") Document doc, HttpServletResponse response) throws IOException {
if (doc.getClient()!=null) {
String type = doc.getType();
storageService.delete(doc.getStorage(),doc.getClient());
documentRepository.delete(doc);
documentService.markDocuments(doc.getClient(), type);
return "redirect:/documents/client/" + doc.getClient().getId();
}else{
String username= SecurityContextHolder.getContext().getAuthentication().getName();
Role role=roleRepository.findByUsernameContainingIgnoreCaseAndActive(username,true);
if (!role.getIsCarrierAdmin()){
return "redirect:/accessDenied";
}
storageService.delete(doc.getStorage(),doc.getCarrierAppointment());
documentRepository.delete(doc);
return "redirect:/carrierAppointment/details/" + doc.getCarrierAppointment().getId();
}
}
#RequestMapping(value="/save/insurance")
public String addInsuranceDoc(#ModelAttribute(value="newInsurance")Insurance newInsurance,#RequestParam("insurance-file") MultipartFile file){
Insurance insurance = insuranceRepository.save(newInsurance);
insurance.setProof(storageService.store(file,newInsurance.getClient()));
insuranceRepository.save(insurance);
documentService.markInsurance(newInsurance.getClient());
return "redirect:/documents/client/"+newInsurance.getClient().getId();
}
#RequestMapping(value="/delete/insurance/{id}")
public String deleteInsurance(Model model,#PathVariable("id")Insurance insurance){
storageService.delete(insurance.getProof(),insurance.getClient());
documentService.markInsurance(insurance.getClient());
insuranceRepository.delete(insurance);
return "redirect:/documents/client/"+insurance.getClient().getId();
}
}
Related
I am getting errors like "failed to create a child event loop/failed to open a new selector/Too many open files" when there are 30 or more concurrent requests...How to solve the above errors? Am I doing anything wrong? I am using Spring boot and Java cassandra driver. Below is the connection file:
public class Connection {
public static Session getConnection() {
final Cluster cluster = Cluster.builder().addContactPoint(ConnectionBean.getCASSANDRA_DB_IP())
.withQueryOptions(new QueryOptions().setConsistencyLevel(ConsistencyLevel.LOCAL_ONE))
.withCredentials(ConnectionBean.getCASSANDRA_USER(), ConnectionBean.getCASSANDRA_PASSWORD())
.withPoolingOptions(poolingOptions)
.build();
final Session session = cluster.connect(ConnectionBean.getCASSANDRA_DB_NAME());
return session;
}
}
Below is the ConnectionBean file which I used in Connection file:
public class ConnectionBean {
public static String CASSANDRA_DB_IP;
public static String CASSANDRA_DB_NAME;
public static String CASSANDRA_USER;
public static String CASSANDRA_PASSWORD;
public ConnectionBean() {
}
public ConnectionBean(String CASSANDRA_DB_IP,String CASSANDRA_DB_NAME,String CASSANDRA_USER,String CASSANDRA_PASSWORD) {
this.CASSANDRA_DB_IP=CASSANDRA_DB_IP;
this.CASSANDRA_DB_NAME=CASSANDRA_DB_NAME;
this.CASSANDRA_USER=CASSANDRA_USER;
this.CASSANDRA_PASSWORD=CASSANDRA_PASSWORD;
}
public static String getCASSANDRA_DB_IP() {
return CASSANDRA_DB_IP;
}
public static void setCASSANDRA_DB_IP(String cASSANDRA_DB_IP) {
CASSANDRA_DB_IP = cASSANDRA_DB_IP;
}
public static String getCASSANDRA_DB_NAME() {
return CASSANDRA_DB_NAME;
}
public static void setCASSANDRA_DB_NAME(String cASSANDRA_DB_NAME) {
CASSANDRA_DB_NAME = cASSANDRA_DB_NAME;
}
public static String getCASSANDRA_USER() {
return CASSANDRA_USER;
}
public static void setCASSANDRA_USER(String cASSANDRA_USER) {
CASSANDRA_USER = cASSANDRA_USER;
}
public static String getCASSANDRA_PASSWORD() {
return CASSANDRA_PASSWORD;
}
public static void setCASSANDRA_PASSWORD(String cASSANDRA_PASSWORD) {
CASSANDRA_PASSWORD = cASSANDRA_PASSWORD;
}
}
Below is the class from where ConnectionBean variables are initialized :
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final String LOGIN_PROCESSING_URL = "/login";
private static final String LOGIN_FAILURE_URL = "/login?error";
private static final String LOGIN_URL = "/login";
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private DataSource dataSource;
#Value("${spring.queries.users-query}")
private String usersQuery;
#Value("${spring.queries.roles-query}")
private String rolesQuery;
#Value("${CASSANDRA_DB_IP}")
public String CASSANDRA_DB_IP;
#Value("${CASSANDRA_DB_NAME}")
public String CASSANDRA_DB_NAME;
#Value("${CASSANDRA_USER}")
public String CASSANDRA_USER;
#Value("${CASSANDRA_PASSWORD}")
public String CASSANDRA_PASSWORD;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
ConnectionBean cb = new ConnectionBean(CASSANDRA_DB_IP, CASSANDRA_DB_NAME, CASSANDRA_USER, CASSANDRA_PASSWORD);
auth.jdbcAuthentication().usersByUsernameQuery(usersQuery).authoritiesByUsernameQuery(rolesQuery)
.dataSource(dataSource).passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// Not using Spring CSRF here to be able to use plain HTML for the login page
http.csrf().disable()
// Register our CustomRequestCache, that saves unauthorized access attempts, so
// the user is redirected after login.
.requestCache().requestCache(new CustomRequestCache())
// Restrict access to our application.
.and().authorizeRequests()
// Allow all flow internal requests.
.requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
// Allow all requests by logged in users.
.anyRequest().authenticated()
// Configure the login page.
.and().formLogin().loginPage(LOGIN_URL).permitAll().loginProcessingUrl(LOGIN_PROCESSING_URL)
.failureUrl(LOGIN_FAILURE_URL)
// Register the success handler that redirects users to the page they last tried
// to access
.successHandler(new SavedRequestAwareAuthenticationSuccessHandler())
// Configure logout
.and().logout().logoutSuccessUrl(LOGOUT_SUCCESS_URL);
}
/**
* Allows access to static resources, bypassing Spring security.
*/
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(
// Vaadin Flow static resources
"/VAADIN/**",
// the standard favicon URI
"/favicon.ico",
// web application manifest
"/manifest.json", "/sw.js", "/offline-page.html",
// icons and images
"/icons/**", "/images/**",
// (development mode) static resources
"/frontend/**",
// (development mode) webjars
"/webjars/**",
// (development mode) H2 debugging console
"/h2-console/**",
// (production mode) static resources
"/frontend-es5/**", "/frontend-es6/**");
}
}
And finally, below is the class through which I am querying cassandra data:
public class getData {
Session session;
public getData(){
session = Connection.getConnection();
getDataTable();
}
private void getDataTable() {
try {
String query = "SELECT * FROM tableName";
ResultSet rs = session.execute(query);
for (Row row : rs) {
/*Do some stuff here using row*/
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
If getConnection() is being invoked for every request, you are creating a new Cluster instance each time.
This is discouraged because one connection is created between your client and a C* node for each Cluster instance, and for each Session a connection pool of at least one connection is created for each C* node.
If you are not closing your Cluster instances after a request completes, these connections will remain open. After a number of requests, you'll have so many connections open that you will run out of file descriptors in your OS.
To resolve this issue, create only one Cluster and Session instance and reuse it between requests. This strategy is outlined in 4 simple rules when using the DataStax drivers for Cassandra:
Use one Cluster instance per (physical) cluster (per application lifetime)
Use at most one Session per keyspace, or use a single Session and explicitely specify the keyspace in your queries
I'm developing a Spring boot application using Thymeleaf as the view technology. I have a html page dashboard.html inside src/main/resources/templates folder, which is being called from inside a controller.
#PostMapping("/users/register")
public String registerUser(#Validated #ModelAttribute User user, Model model) {
User registeredUser = usersDAO.registerUser(user);
if (registeredUser == null) {
return "500error";
}
model.addAttribute("name", user.getName());
model.addAttribute("username", user.getUsername());
model.addAttribute("emailId", user.getEmailId());
return "dashboard";
}
I have some more static html files inside static folder. I want to call dashboard.html from a static html file like using anchor tag <a/>. How can this be done?
I cannot directly link to this file when my app is running locally. For example: localhost:8080/templates/dashboard.html will not work.
You should create a controller for your thymeleaf html template. For example:
#Controller
#RequestMapping("/templates")
public class DashboardController {
#GetMapping("/dashboard")
public ModelAndView dashboard() {
DashboardModel dashboardModel = new DashboardModel();
return new ModelAndView("dashboard", "dashboard", dashboardModel);
}
}
Then you can link to http://localhost:8080/templates/dashboard and get your dashboard.html page.
Of course you can change the #RequestMapping("/templates") and #GetMapping("/dashboard") to control the url as you like.
I am learning how to write REST APIs! How can I store form values into a text file, using rest calls?
index.html
<form action="rest/product/adddata" method="post">
Enter Id:<input type="text" name="id"/><br/><br/>
Enter Name:<input type="text" name="name"/><br/><br/>
Enter Price:<input type="text" name="price"/><br/><br/>
<input type="submit" value="Add Product"/>
</form>
service.java
#Path("/product")
public class ProductService{
#POST
#Path("/adddata")
public Response addUser(
#FormParam("id") int id,
#FormParam("name") String name,
#FormParam("price") float price) {
return Response.status(200)
.entity(" Product added successfuly!<br> Id: "+id+"<br> Name: " + name+"<br> Price: "+price)
.build();
}
}
I want to add value of id, name and price to a file. Where do I need to write function for adding data to file?
write code into
public Response addUser(
#FormParam("id") int id,
#FormParam("name") String name,
#FormParam("price") float price) {
saveFile(id,name,price);
return Response.status(200)
.entity(" Product added successfuly!<br> Id: "+id+"<br> Name: " + name+"<br> Price: "+price)
.build();
}
write code into saveFile to save into file
The best approach for doing this will be to create another class which can write and read from files. And inject that class in this rest endpoint.
Because The direct code in rest endpoint class should be to handle request not to write files
class FormSynchronizer {
public static final File FORM_BASE = new File(...); // The location of directory which will contain all these files
public void storeFile(Map map, String fileName){
File toStoreFile = new File(FORM_BASE, fileName);
/* Write code to store file */
}
}
Inject this class in your rest endpoint class
public class ProductService{
#Inject FormSynchronizer formSynchronizer;
#POST
#Path("/adddata")
public Response addUser(
#FormParam("id") int id,
#FormParam("name") String name,
#FormParam("price") float price) {
Map<String, Object> data = new HashMap<>();
data.put("id", id);
/* put all data you want to store in this map */
formSynchronizer.storeForm(data, "FORM_" + new Date().getTime()); // I used current time prefixed with 'FORM_' string as file name
return Response.status(200)
.entity(" Product added successfuly!<br> Id: "+id+"<br> Name: " + name+"<br> Price: "+price)
.build();
}
}
Use jackson to Convert Map Object to JSON file and vice-versa.
map to / from json file
I am trying to create a login feature for my apache tapestry website, where after logging in, instead of the 'Log In' and 'Register' button, the email of the logged user should be displayed, along with a 'Log Out' button.
Could anyone please tell how should this be implemented the best way?
I can't seem to figure out how should i detect if the user is logged in, in the frontend part, in order to display a different menu options (i am new in tapestry).
Best regards, Marius.
Authentication (of which login is a part) is very application specific. How you define a User (or do you call it a "Customer", for example) is not something the framework does.
Typically, you will have a SessionStateObject representing your User. You can then use something like this in your layout:
<t:if test="user">
<t:logoutLink/>
<p:else>
<t:signInForm/>
</t:if>
Again, components LogoutLink and SignInForm are for you to implement.
The user may be exposed from the Java code as:
#Property
#sessionState(create=false)
private User user;
This says that the user field is linked to a value stored in the HTTP session; further, the User will not be created when the field is first read; instead, your SignInForm component should assign to its user field.
After a little bit of research regarding this matter, i found the following approach:
1) I created an Authenticator interface
public interface Authenticator {
Users getLoggedUser();
boolean isLoggedIn();
void login(String email, String password) throws AuthenticationException;
void logout();
}
2) Also created an AuthenticatorImpl.java class that implements that interface
public class AuthenticatorImpl implements Authenticator {
public static final String AUTH_TOKEN = "authToken";
#Inject
private StartDAO dao;
#Inject
private Request request;
public void login(String email, String password) throws AuthenticationException
{
Users user = dao.findUniqueWithNamedQuery("from Users u where u.Email = '" + email + "' and u.Password = '" + password + "'");
if (user == null) { throw new AuthenticationException("The user doesn't exist"); }
request.getSession(true).setAttribute(AUTH_TOKEN, user);
}
public boolean isLoggedIn()
{
Session session = request.getSession(false);
if (session != null) { return session.getAttribute(AUTH_TOKEN) != null; }
return false;
}
public void logout()
{
Session session = request.getSession(false);
if (session != null)
{
session.setAttribute(AUTH_TOKEN, null);
session.invalidate();
}
}
public Users getLoggedUser()
{
Users user = null;
if (isLoggedIn())
{
user = (Users) request.getSession(true).getAttribute(AUTH_TOKEN);
}
return user;
}
}
3) Created the corresponding binding in the AppModule.java class
public static void bind(ServiceBinder binder)
{
binder.bind(StartDAO.class, StartDAOImpl.class);
binder.bind(Authenticator.class, AuthenticatorImpl.class);
}
4) And on my Layout.java page i used it in the following way
#Property
private Users user;
#Inject
private Authenticator authenticator;
void setupRender()
{
if(authenticator.getLoggedUser().getAccountType().equals("Administrator")){
administrator = authenticator.getLoggedUser();
}
user = authenticator.getLoggedUser();
}
Object onLogout(){
authenticator.logout();
return Login.class;
}
Layout.tml
<t:if test="user">
<span class="navbar-right btn navbar-btn" style="color: white;">
Welcome ${user.Name}! <a t:type="eventLink" t:event="Logout" href="#">(Logout)</a>
</span>
</t:if>
<t:if negate="true" test="user">
<span class="navbar-right">
<t:pagelink page="user/create" class="btn btn-default navbar-btn">Register</t:pagelink>
<t:pagelink page="user/login" class="btn btn-default navbar-btn">Sign in</t:pagelink>
</span>
</t:if>
This worked for me without any problems. Hope that it helps others.
Best regards, Marius.
I use the <p:media> to display static PDF content.
<p:media value="/resource/test.pdf"
width="100%" height="300px" player="pdf">
</p:media>
How can I change it to display dynamic content?
Like as in <p:graphicImage>, the value attribute can point to a bean property returning StreamedContent. This only requires a special getter method for the reasons which is explained in detail in the following answer on using <p:graphicImage> with a dynamic resource from a database: Display dynamic image from database with p:graphicImage and StreamedContent.
In your particular example, it would look like this:
<p:media value="#{mediaManager.stream}" width="100%" height="300px" player="pdf">
<f:param name="id" value="#{bean.mediaId}" />
</p:media>
With
#ManagedBean
#ApplicationScoped
public class MediaManager {
#EJB
private MediaService service;
public StreamedContent getStream() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
} else {
// So, browser is requesting the media. Return a real StreamedContent with the media bytes.
String id = context.getExternalContext().getRequestParameterMap().get("id");
Media media = service.find(Long.valueOf(id));
return new DefaultStreamedContent(new ByteArrayInputStream(media.getBytes()));
}
}
}