I want to download one of my JSP pages as PDF. For example, this is my function which returns to JSP page:
#RequestMapping(value = "/cart", method = RequestMethod.GET)
public String cart(HttpSession httpSession ,final Model model, RedirectAttributes redirectAttributes){
StudentData studentData =(StudentData)httpSession.getAttribute("student");
if(studentData ==null){
redirectAttributes.addFlashAttribute("isFromCartFlag", Boolean.TRUE);
return REDIRECT_PREFIX + "/login" ;
}
final List<ProductData> cartDataFromDb = listofProducts.retrieveCartEntriesFromDb(studentData.getName());
List<ProductData> sessionCart = (List<ProductData>) httpSession.getAttribute("sessionCart");
if (sessionCart != null) {
for (ProductData sessionCartEntryData : sessionCart) {
for (ProductData cartEntryData : cartDataFromDb) {
if(cartEntryData.getProductName().equalsIgnoreCase(sessionCartEntryData.getProductName())){
int quantityOfItem = cartEntryData.getQuantity()+sessionCartEntryData.getQuantity();
sessionCartEntryData.setQuantity(quantityOfItem);
}
}
listofProducts.insertCartEntriesIntoDb(studentData.getName(),sessionCartEntryData.getProductName(),sessionCartEntryData.getQuantity());
}
}
final List<ProductData> cartData = listofProducts.retrieveCartEntriesFromDb(studentData.getName());
List<ProductData> productDataListForCart = new ArrayList<ProductData>();
for (ProductData cartDataEntry : cartData) {
ProductData productData = listofProducts.displayProductDetailsFromProductId(cartDataEntry.getProductName());
if(productData.getProductName().equalsIgnoreCase(cartDataEntry.getProductName())){
cartDataEntry.setBasePrice(productData.getBasePrice());
cartDataEntry.setDiscout(productData.getDiscout());
cartDataEntry.setProductImagePath(productData.getProductImagePath());
productDataListForCart.add(cartDataEntry);
}
}
model.addAttribute("listOfProducts", productDataListForCart);
model.addAttribute("studentData", httpSession.getAttribute("student"));
if(productDataListForCart.isEmpty()){
model.addAttribute("isCartEmptyFlag", Boolean.TRUE);
}
return "CartPage";
}
This function displays cartPage and I want to display a link on this cart page so that if I click on that link the get page will be downloaded as a PDF file with the same format as it displayed in JSP page. This is how my page looks like, in case you're interested:
Spring Web MVC with PDF View Example outlines an approach. In summary, you implement a bean that extends Spring's AbstractView. This view accepts the model from Spring MVC which you can then use to render the PDF using the API of your choice. The article uses a ResourceBundleViewResolver to map the view name to a bean but I personally prefer to use a BeanNameViewResolver.
Spring does provide an AbstractPdfView class but use ann older version of iText for its implementation.
Related
I am trying use a PRG (Post-Redirect-Get) pattern in one of my Spring MVC controller. The controller collects user data from an HTML form, does some processing, stores data in DB and then shows a JSP page. After saving data a redirect should happen and then the JSP page should be displayed.
I also tried to prepend "redirect:" in front of the VIEW_NAME but I get 404 then.
Please guide.
CartPageController.java
#Controller
#RequestMapping("/cartPageController.do")
public class CartPageController {
private static final Logger LOG = Logger.getLogger(CartPageController.class);
private static final String VIEW_NAME = "cart";
#Autowired
protected MasterDao masterDao;
#RequestMapping(method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView processRequest(HttpServletRequest request, HttpServletResponse response) {
LOG.debug("Into the CartPageController...");
HttpSession session = request.getSession();
ModelAndView mav = new ModelAndView();
//create Cart object and store it in session
Cart cart = null;
if (session.getAttribute("cart") != null) {
cart = (Cart) session.getAttribute("cart");
} else {
cart = createCart();
session.setAttribute("cart", cart);
}
LOG.debug("cart = " + cart);
//determine the cart operation
String btnAddToCart = GenericUtils.nullToEmptyString(request.getParameter("btnAddToCart"));
String removeProduct = GenericUtils.nullToEmptyString(request.getParameter("removeProduct"));
String updateProduct = GenericUtils.nullToEmptyString(request.getParameter("updateProduct"));
LOG.debug("btnAddToCart = " + btnAddToCart);
LOG.debug("removeProduct = " + removeProduct);
LOG.debug("updateProduct = " + updateProduct);
if (btnAddToCart.length() > 0) {
addToCart(request, cart);
} else if (removeProduct.length() > 0) {
removeProduct(request, cart);
} else if (updateProduct.length() > 0) {
updateCart(request, cart);
}
//TODO: Should use PRG pattern here
//TRIED TO APPEND "redirect:" here but does not work, gives me 404
mav.setViewName(VIEW_NAME);
return mav;
}
//some more code below here
}
You should redirect to url not a view name. as Spring doc says:
While
the use of RedirectView works fine, if the controller itself creates
the RedirectView, there is no avoiding the fact that the controller is
aware that a redirection is happening. This is really suboptimal and
couples things too tightly. The controller should not really care
about how the response gets handled. In general it should operate only
in terms of view names that have been injected into it.
The special redirect: prefix allows you to accomplish this. If a view
name is returned that has the prefix redirect:, the
UrlBasedViewResolver (and all subclasses) will recognize this as a
special indication that a redirect is needed. The rest of the view
name will be treated as the redirect URL.
you can try
return new ModelAndView(new RedirectView("/page"));
You can't just prepend "redirect:" to your view name which results in redirect:cart and then obviously 404, what you have to do for redirect is to specify the redirect path for e.g.:
redirect:/cart.htm
This should explain it more in details.
You can do this way
redirect:cart.do and have requestmapping in controller which will return cart view.
Hope this will work.
This does not seem to be as easy as I thought. I found some solutions on the web, but they are not working for me. I have an ASP.Net MVC 3 project with the Microsoft ASP.Net Web API 2.1 nuget package installed. Now, I want to be able to read data posted to a web api controller. The data sent will vary, so I cannot used a strongly typed ViewModel.
Here are the solutions I tried:
public void Post([FromBody]string value)
{
...
}
public void Post([FromBody]List<string> values)
{
...
}
public void Post([FromBody]NameValueCollection values)
{
...
}
But my value or values variables are always empty. I know the controller is receiving data however because I can check it by accessing (System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"].Request.Form. It does not look like the proper way to retrieve the data though. There ought to be a cleaner way.
UPDATE:
Here is how I am posting the information:
I am posting the data from another controller in the same web application:
public ActionResult SendEmailUsingService()
{
dynamic email = new ExpandoObject();
email.ViewName = "EmailTest";
email.From = "fromaddress#yahoo.com";
email.To = "toaddress#gmail.com";
email.Fullname = "John Smith";
email.Url = "www.mysite.com";
IDictionary<string, object> data = email;
using (var wb = new WebClient())
{
string url = BaseUrlNoTrailingSlash + Url.RouteUrl("DefaultApi", new { httproute = "", controller = "Emailer" });
var response = wb.UploadValues(url, "POST", data.ToNameValueCollection());
}
return View();
}
And here is what I am getting in my Post web api controller if I declare an httpContext variable like this:
var httpContext = (System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"];
httpContext.Request.Form =
{ViewName=EmailTest&From=fromaddress%40yahoo.com&To=toaddress%40gmail.com&Fullname=John+Smith&Url=www.mysite.com}
httpContext.Request.Form is a System.Collections.Specialized.NameValueCollection {System.Web.HttpValueCollection}
I finally found the answer to my question here:
Web API Form Data Collection
The solution is to use FormDataCollection:
public void Post([FromBody]FormDataCollection formData)
{
...
}
I followed this tutorial, and created this code:
using Glass.Sitecore.Mapper;
using Sitecore.Mvc.Controllers;
using Sitecore.SecurityModel;
using SitecoreCMSMVCBase.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace SitecoreCMSMVCBase.Controllers
{
public class CommentController : SitecoreController
{
ISitecoreContext _context;
ISitecoreService _master;
public CommentController()
: this(
new SitecoreContext(),
new SitecoreService("master"))
{
}
/// <summary>
/// This constructor can be used with dependency injection or unit testing
/// </summary>
public CommentController(ISitecoreContext context, ISitecoreService master)
{
_context = context;
_master = master;
}
[HttpGet]
public override ActionResult Index()
{
var model = _context.GetCurrentItem<CommentPage>();
return View(model);
}
[HttpPost]
public ActionResult Index(Comment comment)
{
var webModel = _context.GetCurrentItem<CommentPage>();
if (ModelState.IsValid)
{
var masterModel = _master.GetItem<CommentPage>(webModel.Id);
if (masterModel.CommentFolder == null)
{
CommentFolder folder = new CommentFolder();
folder.Name = "Comments";
using (new SecurityDisabler())
{
_context.Create(masterModel, folder);
}
masterModel.CommentFolder = folder;
}
using (new SecurityDisabler())
{
comment.Name = DateTime.Now.ToString("yyyyMMddhhmmss");
//create the comment in the master database
_master.Create(masterModel.CommentFolder, comment);
webModel.CommentAdded = true;
}
}
return View(webModel);
}
}
}
Models are identical with tutorial, so I will not paste them.
My route configuration looks like this:
routes.MapRoute(
"CommentController", // Route name
"Comment/{action}/{id}", // URL with parameters
new { controller = "Comment", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
When I navigate to /comment I see this exception:
Glass.Sitecore.Mapper.MapperException: Context has not been loaded
I tried with commenting my route specification (as there was nothing about routes in tutorial), and then error is different (throwing by Sitecore CMS itself):
The requested document was not found
Do you know how to load Sitecore context into custom Controller, and make this simple example work? I was looking everywhere but couldn't find any good answer...
I think this is more a Glass setup issue, rather than an MVC routing problem.
To setup Glass, you need to initialise the context in your application start method in your Global.asax file.
var loader = new Glass.Sitecore.Mapper.Configuration.Attributes.AttributeConfigurationLoader(
"Glass.Sitecore.Mapper.Tutorial.Models, Glass.Sitecore.Mapper.Tutorial");
Glass.Sitecore.Mapper.Context context = new Context(loader);
For other Glass-setup related stuff I recommend following the first tutorial on the glass.lu website.
http://www.glass.lu/tutorials/glass-sitecore-mapper-tutorials/tutorial-1-setup/
This method doesn't need Glass at all!
First step is to set your route in Global.asax file.
routes.MapRoute(
"DemoController", // Route name
"Demo/{action}/{param}", // URL with parameters
new { controller = "Demo", action = "Index", param = "", scItemPath = "/sitecore/content/DemoHomePage" } // Parameter defaults
);
Notice that controller is not taken as parameter, but is fixed, to prevent handling it by Sitecore. More info here and here. Notice that there is one additional parameter - scItemPath. It contains path to item which by default will be included in page context.
Having this route our traffic from /demo is handled by DemoController and Index action. Inside this action all you need is to add is this line:
Sitecore.Data.Items.Item item = Sitecore.Mvc.Presentation.PageContext.Current.Item;
item variable will contain your Sitecore item pointed by scItemPath.
And that's all - it should work well now - hope it helps!
I am trying to read blob type image which is coming from Database. My method in controller. Only Image file is displaying on JSP nothing else
#RequestMapping(value = "/showDetails")
public ModelAndView showDetails(#RequestParam("doc") int id,
HttpServletResponse responce) {
ModelAndView mView = new ModelAndView();
File file = documentDao.getFileDetail(id);
byte[] bytes = null;
try {
OutputStream op = responce.getOutputStream();
int length = (int) file.getContent().length();
bytes = file.getContent().getBytes(1, length);
op.write(bytes);
op.flush();
op.close();
responce.setContentType("image/gif");
mView.addObject("image", op);
} catch (Exception e1) {
e1.printStackTrace();
}
mView.addObject("file", file);
mView.setViewName("filedetails");
return mView;
}
The above method in my controller class. And I want to render image as well as some text on JSP. But only image is coming in Browser.
You can't do it this way in Spring (in Servlets more precisely). Create two different controllers -- one will serve image and another will return JSP page with text. To get image at page just properly set value of src attribute of img tag: it should point to first controller.
I am working in Asp.net MVC and have a peculiar requirement for which I have no idea.
What I want is that when a user request a particular URL from my site, I want to visit some preset URL in the database and extract some data and bind them to View before rendering.
For example, If you visit mysite.com/Search/Index, then in my action method Index, i want to visit the anothersite.com/someparticular/url, extract the value in <div> with id="searclbl", bind it to my view and render the page.
I need to read the HTML because the sites I am working with don't offer any Web services or RSS.
Any sort of help or guidance in this matter is appreciated.
I believe you might be able to pull this off using HtmlAgilityPack (which can be installed via a NuGet package inside your project).
For example:
Let’s assume your Index View of the SearchController is strongly typed to the following ViewModel:
public class SearchViewModel
{
public string DivElement { get; set; }
//other properties...
}
This is the Index ActionResult():
public ActionResult Index()
{
var model = new SearchViewModel();
model.DivElement = GetDivFromWebSite();
return View(model);
}
The GetDivFromWebSite() method is where I use HtmlAgilityPack to fetch information from another web site and is defined like so:
private string GetDivFromWebSite()
{
var baseUrl = new Uri("http://www.anotherdomaine.com");
HtmlAgilityPack.HtmlDocument document = new HtmlDocument();
using (WebClient client = new WebClient())
{
document.Load(client.OpenRead(baseUrl));
}
if (document == null) return "nothing found!";
var div = document.DocumentNode.SelectNodes("//div[#id='missing-category']").FirstOrDefault();
return div.InnerHtml;
}
This might do the trick!