我写的一堂课有问题。该类的目的是为<spring:message code="key" />
用于为网站提供双语支持的applicationResource.properties文件添加/删除/更新。手动与属性文件交互可以很好地工作,但是我有一个更大的需求,因此我建立了一种允许从数据库中进行更改的方式。这给了我一个非常动态和灵活的系统,可以在其中使用。
但是,有一个问题。甚至在使用此功能进行一次更改之后的某个时候,法语字符最终都会被更改。例如Déconnexion
变成Déconnexion
。在记事本++中查看时,其第一个Déconnexion
,然后损坏为D\u00C3\u00A9connexion
。此示例是原始属性文件的一部分。
原始(非临时)属性文件的text file encoding
设置为other: UTF-8
。项目属性text file encoding
设置为inherited from container (Cp1252)
。我尝试更改为Other: UTF-8
,但没有更改。
所以我的问题是,是什么导致法语字符损坏以及如何解决?我在下面提供了完整的课程。
更新:在StephaneM的帮助下,我能够准确找到导致损坏的原因,但尚未解决。 AR类中的loadProperties()函数。临时AP文件一旦加载,法语字符就会损坏。这使我怀疑创建临时AP文件的原始过程正在使用不同的编码。因此,我将不得不对其进行跟踪。
package pojo;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
/*
* Purpose of this class is to handle all the ApplicationResource(_fr).properties interactions
* so that there is one unified location handling this, instead of code duplication.
*/
public class AR{
public final String en_path = "/ApplicationResources.properties";
public final String fr_path = "/ApplicationResources_fr.properties";
private Properties en_prop = null;
private Properties fr_prop = null;
public AR()
{
loadProperties();
}
private void loadProperties()
{
InputStream en_is = null;
InputStream fr_is = null;
try {
this.en_prop = new Properties();
this.fr_prop = new Properties();
en_is = this.getClass().getResourceAsStream(en_path);
fr_is = this.getClass().getResourceAsStream(fr_path);
en_prop.load(en_is);
fr_prop.load(fr_is);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private boolean keyExist(String mykey, String mypath) //deprecated due to better code/method
{
Properties test_prop = null;
InputStream is = null;
try {
test_prop = new Properties();
is = this.getClass().getResourceAsStream(mypath);
test_prop.load(is);
Set<Object> keys = test_prop.keySet();
for(Object k:keys) {
String key = (String)k;
//System.out.print(key + " ");
if(key.equals(mykey))
{
return true;
}
}
//System.out.println(" ");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
public boolean en_keyExist(String mykey)
{
//searches english file
loadProperties();
return en_prop.containsKey(mykey);
//return keyExist(mykey, en_path); //original method
}
public boolean fr_keyExist(String mykey)
{
//searches french file
loadProperties();
return fr_prop.containsKey(mykey);
//return keyExist(mykey, fr_path); //original method
}
public boolean en_fr_keyExist(String mykey)
{
//searches both english and french files
loadProperties();
return (en_prop.containsKey(mykey) && fr_prop.containsKey(mykey));
//return (keyExist(mykey, en_path) && keyExist(mykey, fr_path)); //original method
}
public String en_returnProperty(String mykey)
{
//returns null if key does not exist
loadProperties();
return this.en_prop.getProperty(mykey);
}
public String fr_returnProperty(String mykey)
{
//returns null if key does not exist
loadProperties();
return this.fr_prop.getProperty(mykey);
}
public void appendProperty(Properties new_en_prop,Properties new_fr_prop)
{
//note: during a test, setProperty (used in populating the properties) does not allow duplicates, it overwrites.
//So, load the existing properties, and for each new property add it
loadProperties();
for(Object key : new_en_prop.keySet())
{
en_prop.setProperty((String)key, new_en_prop.getProperty((String)key));
}
try (OutputStream en_os = new FileOutputStream(getClass().getResource(en_path).getFile(),false);)
{
en_prop.store(en_os, null);
} catch (IOException e) {
e.printStackTrace();
}
for(Object key : new_fr_prop.keySet())
{
fr_prop.setProperty((String)key, new_fr_prop.getProperty((String)key));
}
try (OutputStream fr_os = new FileOutputStream(getClass().getResource(fr_path).getFile(),false);)
{
fr_prop.store(fr_os, null);
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean appendProperty(String mykey, String en_val, String fr_val) //appears to have timing error due to only saving last value
//due to timing error this function is only suitable for single additions
//due to the timing error, tried returning boolean to have it finished but was not successful
//setting the class variables to static did not solve the timing issue
{
loadProperties();
en_prop.setProperty(mykey, en_val);
try (OutputStream en_os = new FileOutputStream(getClass().getResource(en_path).getFile(),false);)
{
en_prop.store(en_os, null);
} catch (IOException e) {
e.printStackTrace();
}
fr_prop.setProperty(mykey, fr_val);
try (OutputStream fr_os = new FileOutputStream(getClass().getResource(fr_path).getFile(),false);)
{
fr_prop.store(fr_os, null);
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
public void en_setProperty(String mykey, String en_val)
//suspected timing issue, use only for singular changes
{
loadProperties();
en_prop.setProperty(mykey, en_val);
try (OutputStream en_os = new FileOutputStream(getClass().getResource(en_path).getFile(),false);)
{
en_prop.store(en_os, null);
} catch (IOException e) {
e.printStackTrace();
}
}
public void fr_setProperty(String mykey, String fr_val)
//suspected timing issue, use only for singular changes
{
loadProperties();
fr_prop.setProperty(mykey, fr_val);
try (OutputStream fr_os = new FileOutputStream(getClass().getResource(fr_path).getFile(),false);)
{
fr_prop.store(fr_os, null);
} catch (IOException e) {
e.printStackTrace();
}
}
public void compareResources()
{
Properties new_en = new Properties();
Properties new_fr = new Properties();
for(Object key : en_prop.keySet())
{
new_en.setProperty((String)key, en_prop.getProperty((String)key));
}
for(Object key : fr_prop.keySet())
{
new_fr.setProperty((String)key, fr_prop.getProperty((String)key));
}
Properties temp = (Properties) new_en.clone();
for(Object key : temp.keySet())
{
if(new_fr.containsKey((String) key))
{
new_fr.remove(key);
new_en.remove(key);
}
}
for(Object key : new_en.keySet())
{
System.out.println("English only key: " + ((String)key));
}
for(Object key : new_fr.keySet())
{
System.out.println("French only key: " + ((String)key));
}
}
}
该类的示例用例,直接从应用程序中获取,但进行了一些编辑,因此此处仅相关部分
AR testing = new AR();
Properties en_prop = new Properties();
Properties fr_prop = new Properties();
final String test_prod_cur = "{call BILINGUAL_VALUES(?)}";
ResultSet rs = null;
try (
Connection connection = jdbcTemplate.getDataSource().getConnection();
CallableStatement callableStatement = connection.prepareCall(test_prod_cur);
)
{
callableStatement.registerOutParameter(1, OracleTypes.CURSOR);
callableStatement.executeUpdate();
rs = (ResultSet) callableStatement.getObject(1);
while (rs.next())
{
String thead = rs.getString(1);
en_prop.setProperty(keyheader+thead, rs.getString(2));
fr_prop.setProperty(keyheader+thead, rs.getString(3));
//testing.appendProperty(keyheader+thead, rs.getString(2), rs.getString(3)); //has a timing issue, ends up only appending final value
}
}
catch (SQLException e)
{
System.out.println("SQLException - bilingual values");
System.out.println(e.getMessage());
}
testing.appendProperty(en_prop, fr_prop);
答案 0 :(得分:1)
关于这个问题:“是什么导致我的法语字符损坏以及如何解决?”,答案在文档(Properties.store())中:
公共无效存储(OutputStream输出, 字符串注释) 引发IOException
在此属性中写入此属性列表(键和元素对) 表以适合加载到 使用load(InputStream)方法的属性表。
此“属性”表的默认表中的属性(如果有) 不会用这种方法写出来。
此方法输出注释,属性键和值 与store(Writer)中指定的格式相同,并具有以下内容 差异:
- 使用ISO 8859-1字符编码编写流。
- 注释中非拉丁1的字符表示为\ uxxxx,代表其相应的unicode十六进制值xxxx。
- 对于适当的十六进制值xxxx,属性键或值中小于\ u0020的字符和大于\ u007E的字符被写为\ uxxxx。
答案 1 :(得分:0)
我不是唯一遇到此问题的人,我设法找到了另一个问题,而这是answers之一,它使我提出了解决方案。我要感谢另一个site,让我知道要包含的内容。
只有四行添加或更改,我将列出它们,然后给出完整的功能。
import java.io.Reader;
Reader reader = new InputStreamReader(fr_is, "UTF-8");
fr_prop.load(reader); //instead of fr_prop.load(fr_is);
reader.close();
完整功能
import java.io.Reader;
private void loadProperties()
{
InputStream en_is = null;
InputStream fr_is = null;
try {
this.en_prop = new Properties();
this.fr_prop = new Properties();
en_is = this.getClass().getResourceAsStream(en_path);
fr_is = this.getClass().getResourceAsStream(fr_path);
Reader reader = new InputStreamReader(fr_is, "UTF-8");
en_prop.load(en_is);
fr_prop.load(reader);
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
通过介绍读者并使用它,它清除了法语字符损坏。
我应该提到的是,在进行上述更改并使其正常工作之前,我将可以找到的每个文件属性都更改为UTF-8。 site给您我所做的更改。这是一个不错的page,可以帮助我确认编码。