Persisting Arabic/Hebrew in MariaDB, received from webform - spring-mvc

I have a small Spring 4 application that receives data from a form, persists it in MariaDB, displays it on a webpage and if asked returns the data written into an xls (MS Excel) document using Apache POI.
The application works fine for English text.
Here are the commands I ran to create and populate the db table:
CREATE DATABASE testdb COLLATE 'utf16_general_ci';
use testdb;
create table testtable( id INTEGER PRIMARY KEY AUTO_INCREMENT, text1 VARCHAR(100), text2 VARCHAR(100), text3 VARCHAR(200));
INSERT INTO testtable (text1,text2,text3) VALUES ('אבג','דהו','זחט');
Here is the JSP page for displaying and making requests:
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%# taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-16">
</head>
<body>
<table border=1>
<tr><th>TEXT1</th><th>TEXT2</th><th>TEXT3</th></tr>
<c:forEach items="${rowList}" var="row">
<tr>
<td>${row.getText1()}</td>
<td>${row.getText2()}</td>
<td>${row.getText3()}</td>
</tr>
</c:forEach>
<tr><td><br><form method="GET" action="/clear"><input type="submit" value="CLEAR TABLE" /></form></td>
<td><br><form method="GET" action="/getxls"><input type="submit" value="download XLS file" /></form></td>
<td></td>
</tr>
</table>
<br>
<table border=1>
<tr><td>
<form method="POST" action="/add" accept-charset="UTF-16" >
<label>TEXT1</label>
<input type="text" name="text1" /><br>
<label>TEXT2</label>
<input type="text" " name="text2" /><br>
<label>TEXT3</label>
<input type="text" name="text3" />
<br>
<input type="submit" />
</td></tr>
</table>
</form>
</body>
</html>
And here is the single controller for the application:
#Controller
public class HomeController {
#Autowired
UserDao userDao;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String index(ModelMap model){
model.addAttribute("rowList", userDao.getUserList());
return "home";
}
#RequestMapping(value = "/clear", method = RequestMethod.GET)
public String clearTable(){
userDao.deleteAllUsers();
return "home";
}
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addCoding(
#RequestParam("text1") String t1,
#RequestParam("text2") String t2,
#RequestParam("text3") String t3,
ModelMap model
) throws Exception{
User b = new User(java.net.URLDecoder.decode(t1,"UTF-16"), t2, t3);
userDao.addUser(b);
model.addAttribute("rowList", userDao.getUserList());
return "home";
}
#RequestMapping(value = "/getxls", method = RequestMethod.GET )
public void export1( HttpServletResponse response ) throws IOException {
List<User> users = userDao.getUserList();
Workbook wb = new HSSFWorkbook();
CreationHelper createHelper = wb.getCreationHelper();
Sheet sheet = wb.createSheet("new sheet");
// creating headers for data columns
Row row = sheet.createRow(0);
row.createCell(0).setCellValue("TEXT1");
row.createCell(1).setCellValue("TEXT2");
row.createCell(2).setCellValue("TEXT3");
int rowIndex = 1;
for(User user : users){
row = sheet.createRow(rowIndex);
row.createCell(0).setCellValue(createHelper.createRichTextString(user.getText1()));
row.createCell(1).setCellValue(createHelper.createRichTextString(user.getText2()));
row.createCell(2).setCellValue(user.getText3());
rowIndex++;
}
response.setHeader("Content-Disposition","attachment; filename=data.xls");
ServletOutputStream out = response.getOutputStream();
wb.write(out);
out.flush();
out.close();
}
}
The data object in the controller is called User but it really is just and int for db id and three Strings
Filling the form with the same Hebrew input as in the MariaDB console submitting it results in the following:
In all of the three result displays, contents of line 1 and 3 are the same. (Or at least the input was)
Line 1 was entered using MariaDB console.
Line 3 was entered in the web page.
How can I process the web request so in the xls file lines 1 and 3 are the same?
Also how can I properly display data of line 1 on the web page?

Correction to the JPS page:
1) adding
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="ISO-8859-1"%>
to the top of the document, this will properly display valid data pulled from the DB.
2) in the <form> rag, changing the value of attribute accept-charset from UTF-16 to ISO-8859-1. This will return Arabic and Hebrew characters in the form of &#xxxx; where each x is a decimal digit.
Correction to logic - turning the said &#xxxx; characters into proper Arabic/Hebrew characters:
The hebrew 'Aleph' = 'א' passed as א.
In java String.valueOf(Character.toChars(Integer.parseInt("1488", 10))); will return the proper 'א' character; so I added the following funcion to run on the input first thing in the controller:
public static String y(String txt){
String formatedString = "";
char[] charArr = txt.toCharArray();
for (int i=0; i<charArr.length; i++){
if(charArr[i] != '&')
formatedString += charArr[i];
else {
if (i+5 <= charArr.length && charArr[i+1] == '#'){
String temp = "";
for (int j=i+2;j<=i+5;j++)
temp += charArr[j];
if (temp.matches("-?\\d+(\\.\\d+)?")){
formatedString += String.valueOf(Character.toChars(Integer.parseInt(temp, 10)));
i=i+6;
}
} else
formatedString += charArr[i];
}
}
return formatedString;
}

Do not use utf-16. Use UTF-8, which is called utf8 or utf8mb4 inside MySQL.
The
On connecting you must specify the encoding in use by the client.
Columns in tables must be declared CHARACTER SET utf8 (or utf8mb4).
(Arabic and Hebrew are both handled.)
If you actually do have UTF-16 encoding at the client, then you can connect with utf16. But I recommend using utf8 or utf8mb4 in the tables. MySQL will convert on the fly.

Related

Get FileSize in Server is always zero

I'm doing a file upload function in my ASP.NET MVC web system. The file upload function is working, so the next step I do is to validate the file size.
Please see the attached codes
Partial form GEDocumentInfoForm.ascx:
<input type="file" name = "Files" class = "multi" id = "myFile"/>
Main Form Create.aspx
<asp:Content ID="Content4" ContentPlaceHolderID="ContentCph" runat="server">
<script type="text/javascript">
$(document).on('click', '#btnCreateDocument', function () {
$('#btnCreateDocument').attr('disabled', 'disabled'); // prevent resubmit
Checksize()
document.body.style.cursor = 'wait';
});
function Checksize() {
alert(document.getElementById("myFile").tagName);
var k = document.getElementById("myFile").files[0].size;
alert("file size in KB " + k / 1024);
}
</script>
<% Using (Html.BeginForm("Create", "GEDocument", FormMethod.Post, New With {.enctype = "multipart/form-data", .id = "form"}))%>
<input type="submit" name="Save" value="<%= Detail.Save %>" id="btnCreateDocument" />
<div id="Div1">
<% Html.RenderPartial("GEDocumentInfoForm", Model) %>
</div>
<% End Using%>
</asp:Content>
The file size validation (not more than 2048B) was working fine in localhost. So, after that I published it and deploy in my development server. When I run it, somehow it can pass through my validation. After check in debug mode of web browser, it returns 0 for the file size.
var k = document.getElementById("myFile").files[0].size;
I've tried to search solutions to see if anyone hit the similar issue before. End up, I have to use server validation in my Controller.
Dim fileZs As HttpFileCollectionBase = Request.Files
For z As Integer = 0 To (fileZs.Count - 1)
Dim file As HttpPostedFileBase = fileZs(z)
If Not IsNothing(file) AndAlso (file.ContentLength / 1024) > 2048 Then
errors.Concat(New RuleViolation(Message.EmailMustHaveValue, "SelectedToEmails"))
End If
Next
Web.Config (added the configuration so that it can pass ActionFilterAttribute in Controller due to Maximum request too long)
<system.web>
<httpRuntime maxRequestLength="1048576" />
</system.web>
I think that server validation is not user-friendly. I wish there are some answers from the experts if anyone faced the issue like me in doing Client validation to check file size in file upload feature.
Why is it always return 0 after published to development server?
Is it related to server security? As I know we are getting FileName as C:\fakePath\myFileName. Could it be some relationship over here?
here a full working example, note Request.Files is an array, if you are sending only one file you need to pick first item.
the right property to check is ContentLength
also check if in your folder the uploaded file exists after upload, because you need to have write permission in the folder where you are uploading
[HttpPost]
public ActionResult Upload()
{
if (Request.Files.Count > 0)
{
var file = Request.Files[0];
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Images/"), fileName);
file.SaveAs(path);
}
}
//............
}

Reading CSV File in hosted application

I have created an MVC ASP.Net application and hosted in within IIS. Part of my app allows for users to upload a csv file. The data then needs to be read out of the csv and into an object to be used elsewhere.
The problem I have is when hosted in IIS the file can not be read. Here is my code:
using (StreamReader CsvReader = new StreamReader(filePath))
{
MessageHandler.NewNote("Opened CSV Reader");
string inputLine = "";
int lineNumber = 0;
while ((inputLine = CsvReader.ReadLine()) != null && !string.IsNullOrEmpty(inputLine))
{
//Do something here
}
}
Can someone please advise how I get this working. The filepath is generated using the following upload form:
<div id="UploadForm">
<% using (Html.BeginForm("FileUpload", "ImportExport", Model,
FormMethod.Post, new { enctype = "multipart/form-data" }))
{%>
<input name="uploadFile" type="file" accept=".csv" style="width:70%;" />
<input type="submit" value="Upload File" />
<%} %>
</div>
The filePath is coming from the client, there should be no file existing on the server at the given file path.
You need to read the data from the Stream coming from the upload form instead of the file path.
Please refer to the following link
http://msdn.microsoft.com/en-us/library/system.web.httprequest.inputstream.aspx

play framework: http requests : server : get(),post(),put() - can't understand how it works

Soooooo, i've looked around and tried to understand how the 'http' requests are working ... i've tried some methods, but i failed 'with flying colors' (ok, sorry for that).
I think i have problems understanding how everything works....
For example...I have this register form:
#(page: String, isLoggedIn: Boolean, userInfo: NewUser)
#import bootstrap3._
#Main(page, isLoggedIn, userInfo) {
<script src='#routes.Assets.at("javascript/index.js")'></script>
<br><br><br>
<br>
<form action="#routes.Application.addUser()" method="POST">
<div class="col-md-offset-1 col-md-4">
<h3><b>Register : </b></h3>
<br>
Username :
<input type="input" name="username" class="form-control"><br>
First Name :
<input type="input" name="first_name" class="form-control"><br>
Last Name :
<input type="input" name="last_name" class="form-control"><br>
Password:
<input type="password" name="password" class="form-control"><br>
Repeat Password :
<input type="password" name="re_password" class="form-control"><br>
<input type="submit" class="btn">
</div>
</form>
}
with this model:
...
public class NewUser extends Model{
#Id
public String Id;
public String username;
public String first_name;
public String last_name;
public String password;
public String re_password;
+getters and setters
}
And i want to make a method to add the user to my database using my server...
public static Result addUser(){
String url = "http://localhost/my-server-url";
NewUser user = Form.form(NewUser.class).bindFromRequest().get();
// ? String charset = "ISO-8859-1";
// ? WSRequest wsRequest = WS.url(url);
// ? HttpResponse wsResponse = wsRequest.post();
// ? String responseString = wsResponse.getString(charset);
}
********** And what now ... !? - how does the server know how to fill my database? (i think the url helps here ... the register form should have the same structure like my DB?)
*********Or how can i tell him to give me back something from the data base in a list (for example)?
Can someone please explain how it all works !?
Thanks a lot ...
How does the server know how to fill my database?the register form should have
the same structure like my DB?
Play contains several different bind() methods. Some of them supports JSON or request values, the others Map<String, String[]> instances. They all point internally to public Form<T> bind(Map<String,String> data, String... allowedFields) method. As the name of this method suggest, it's responsible for handling submitted data. It means that inside this method we can find a fragments about:
received data normalization (translation the unordered data to interpreted object, in this case DataBinder instance):
DataBinder dataBinder = null;
Map<String, String> objectData = data;
if(rootName == null) {
dataBinder = new DataBinder(blankInstance());
} else {
dataBinder = new DataBinder(blankInstance(), rootName);
objectData = new HashMap<String,String>();
for(String key: data.keySet()) {
if(key.startsWith(rootName + ".")) {
objectData.put(key.substring(rootName.length() + 1), data.get(key));
}
}
}
So the line
Form.form(NewUser.class).bindFromRequest()
in your controller creates an form object of NewUser type and maps the request coming to the NewUser object fields interlnally as shown above code.So the form field name should be same as your entity fields name in order to be persisted in database.
And what now ... !?
Now after doing
NewUser user = Form.form(NewUser.class).bindFromRequest().get();
in your controller you have to pesist this entity by doing
user.save();
It will be saved in database.You can also send this object to you model call save method there.
How can i tell him to give me back something from the data base in a
list (for example)?
Souppose you have to find all the NewUser saved in database .So you can fetch the list by
public static Finder<Integer, Member> find = new Finder(Integer.class, NewUser.class);
public static List<NewUser> all(){
return find.all();
}
in your model class and call this all() method in your controller .
You can always take help from play samples provided in folder that you downloaded.
Note: I am assuming here you are using default orm of play i.e. ebean
Source1 Source2

How can I send a list in BeginForm()?

Can someone please help me with this problem? At the bottom of my view just before the page loads I create an array of checkboxes like this:
foreach (var course in courses.Select((x, i) => new { Data = x, Index = i }))
{
int currentIndex = course.Index;
String selectedday = "";
String selectedteacher = "";
if (cnt++ % 4 == 0)
{
#: </tr> <tr>
}
#: <td >
<br /><br /><br />
<input type="checkbox" id="checkbox"
name="selectedCourses"
value="#course.Data.CourseID"
#(Html.Raw(course.Data.Assigned ? "checked=\"checked\"" : ""))
/>
I use the same loop to add the assigned state to a list like this:
bool theNewString=course.Data.Assigned ;
String a=theNewString.ToString();
assignedCourses.Add(a);
I defined a list variable at the top of the page so that it can be accessed by the form-wide like this:
#{List<String> assignedCourses =new List<String>(); }
Now I want to send that variable to the controller and this is where things get muddy. If I send a string like this it works fine:
Razor markup
String postedData = "literalString";
#using (Html.BeginForm("Action", "Controller", new { assigned = # postedData }))
Action
[HttpPost]
public ActionResult Edit(int id,List<String> assigned){}
Now if I try this:
#{List<String> assignedCourses =new List<String>(); }
#using (Html.BeginForm("Action", "Controller", new { assigned = #assignedCourses }))
And nothing comes through to the controller. It’s like the list is emptied just before posting. How can send my list to the controller?
I think the way you are trying to create the query string/postback url for the form using the list is wrong and will not produce a properly formatted string.
Maybe try something like this:
#{
List<string> ExampleList = new List<string>();
ExampleList.Add("True");
ExampleList.Add("False");
string param = string.Join("&", ExampleList.ToArray());
}
#using (Html.BeginForm("index", "home", new { #someparam = (new HtmlString(param)) })) { }
This would require you to split the single string up into an array when the action method receives it.
alternatively you can try using RouteValueDictionary instead of list, but this does not support duplicate keys.
Also for checkbox creation try using #Html.CheckBox() as this will automatically create a second hidden input set to false. HTML Forms don't post back checkbox values when they are unchecked, so the second hidden input with the same name will be posted back and you will know it has been unchecked or not checked. MVC will interpret values of "True, False" for the same form key/input name as True and False when just the hidden input with the "False" value is posted back.

How can I populate the pull down menu using data from a database?

I keep on getting this error message.InvalidCastException was unhandled by the user, Unable to cast object of type 'System.Int32' to type 'System.String'.
I've been told the view data value for bloodtype is not correct. Just trying to figure out how to determine the value.
I'm new to asp.net therefore don't understand too much at the moment.
<select name="bloodtype">
<% List<Hospital.bloodtype> bloodtypeList = (List <Hospital.bloodtype>) ViewData["bloodtypeList"];
foreach (Hospital.bloodtype st in bloodtypeList)
{
%>
<option value="="<%= st.bloodcode%>"><% *if (st.bloodcode==(String) ViewData["bloodtype"])* Response.Write("Selected"); %><% Response.Write(st.meaning);%>></option>
<% } %>
<option value="0" <% if ((Int32) ViewData["bloodtype"]==0) Response.Write("Selected");%>>
</option>
public void HospitalInit()
{
hospitalSQLEntities db = new hospitalSQLEntities();
ViewData["bloodtypeList"] = db.bloodtypes.ToList();
ViewData["patientid"] = "";
ViewData["patientname"] = "";
ViewData["bloodtype"] = 0;
ViewData["junk"] = "";
ViewData["spam"] = "";
ViewData["comments"] = "";
ViewData["formmessage"] = "";
}
public ObjectSet<bloodtype> bloodtypes
{
get
{
if ((_bloodtypes == null))
{
_bloodtypes = base.CreateObjectSet<bloodtype>("bloodtypes");
}
return _bloodtypes;
}
}
The best way to do this is to define a list of bloodtypes in your code behind like:
private List<bloodtype> _bloodtypes = new list<bloodtype>();
Next, you can use an ASP.NET combobox control that you place on your page and to which you databind the specified list (also in the code behind), like so:
public void PageLoad(){
_bloodtypes = GetBloodTypes();
myCombobox.DataSource = _bloodtypes;
myCombobox.DataBind();
}
private IList<bloodtype> GetBloodTypes(){
// Get some bloodtypes
return new List<bloodtype>();
}
Of course, before databinding, you need to fill the list (as seen above).
Instead of casting use convert
Convert.ToInt32(ViewData["bloodtype"])

Resources